forked from alexeygritsenko/Scala-Lections
-
Notifications
You must be signed in to change notification settings - Fork 0
/
lec03.scala
122 lines (103 loc) · 5.04 KB
/
lec03.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
// Обращение к массиву
arr(i)
arr(i) = j
// Список
var lst = new List[Int]()
val l2 = List(3, -5, 92)
l2(1) // -5, сложность O(n), у массива O(1)
// Эти операции очень быстрые, т.к. список - линейный.
l2.head // Возвращает элемент
l2.tail // Возвращает ссылку на второй и т.д.
// В середину лучше не добавлять элементы
// Добавить в начало:
l2.prepend(x) // С таким видом записи не работаем
l2.prepend(x) // => x 3 -5 92
// У prepend есть синоним
x::l2
3::-5::-92::Nil // , где Nil не пустая ссылка
// Null != Nil != null
// Nil - литеральный пустой список
(3::-(5::(-92::Nil)))
// Для добавления в конец список
l2.append(x) // Сложность O(n), а у prepend сложность O(1), так что лучше не использовать для больших списков
// Кортеж - некоторый набор данных, объединенный в логический ряд. Кортеж имеет следующие отличия от списков/массивов:
// 1) Имеют фиксированную длину;
// 2) Неизменяемая структура данных;
// 3) Элементы должны быть однотипные.
// 3а) Кортеж типизирован: он состоит из двух типов в отличие от массивов И списков.
val t1 = (2, "Два")
// t1:(Int, String)
// У любого кортежа есть такого рода поля:
t1._1 // 2
t1._2 // "Два"
val t2 = ("Петров", "ВПР21", 72.5, 2011)
:(String, String, Double, Int)
// Кортеж может быть составной
val p3 = ((2.5, 3.14), (3.2, 5.0))
// Кортежи можно "присваивать" (грубо говоря0
val (x, y) = (2, 3) // Нотировать можно x, y, а можно весь кортеж
// Option проверяет наличие значения, при этом не говорит что за значение
// Он распадается на Some(x) и None
// Some(x) - хранит ли x
// None - ничего
Some(3)
Some("else")
Some((2, 15)) // Внутри именно кортеж, поэтому нельзя писать без скобок
val o1 = Some(5)
val o2 = None
o1.get // 5 (get редко используется)
o2.get // Исключение
o1.isDefined // Определен
o1.isEmpty // Не определен
// Если в списке элементов нет, то
l2.head // исключение, поэтому у всех коллекций и т.п. есть headOption
// Если элемент есть, то headOption возвращает первый элеммент, иначе None
// С tail такая же ситуация.
val o2 = None
o2.getOrElse(3) // 3
(o1 getOrElse 17) // 5 (потому что o1 == 5)
// Лямбда выражения
def add(x:Int, y:Int):Int = x + y
// def add:(Int, Int):Int => Int
// Ноитурем f2 или x
val f2:Double => Double = x => 2*x
val f3 = math.sin
// x => 2*x - если x встречается один раз в выражении, то x можно заменить на _ и убрать из параметров
val f3:Int => Int = _*2
// Выражение, которое встречалось в лекции ранее
map {_.toInt} // - это лямбда
val f4:(Int, Int) => Int = (_+_) // (x,y) => x + y
// ...
// Функция табулирования
// ((Double, Double), Double, Double => Double) => Unit
def tabulate(interval:(Double, Double), step:Double, f:Double => Double):Unit
// Передача в функцию может осуществляться 2 методами
// До этого мы использовали передачу по функцию
f(5) // Вызывалось f, передавалось 5
f(bar(x)) // Вызывался bar, передавалось x, вызывалась f, передавался результат bar
// Передача по имени
def f(x: => Int) {
println(x)
println(x)
}
f(5) // 5 и 5
f(bar(x)) // Значение параметра переносится из точки вызова в точку использования
def f(x: => Int) {
println(x) // Вызывает bar здесь
println(x) // Вызывает bar и здесь!
// Это и есть передача по имени
}
// Компилятор это превращает примерно в такой вид:
f(() => bar(x))
def f(x:Unit => Int) {
println(x) // println(x())
println(x)
}
// Последствием этого является
def f(x:=>Int) {
if(...)
// bar - делает затратное вычисление, но
// т.к. до кода не дойдет (if не выполнится),
// вычисления не произойдут
println(x)
}