Scala tuple unwrapping nuance
Я заметил следующее поведение в scala при попытке распаковать кортежи в vals:
scala> val (A, B, C) = (1, 2, 3)
<console>:5: error: not found: value A
val (A, B, C) = (1, 2, 3)
^
<console>:5: error: not found: value B
val (A, B, C) = (1, 2, 3)
^
<console>:5: error: not found: value C
val (A, B, C) = (1, 2, 3)
^
scala> val (u, v, w) = (1, 2, 3)
u: Int = 1
v: Int = 2
w: Int = 3
Это потому, что механизм соответствия шаблону scala автоматически предполагает, что все идентификаторы, начинающиеся с capitals внутри шаблонов, являются константами, или это связано с какой-то другой причиной?
Спасибо!
Ответы
Ответ 1
Да, и это становится хуже:
val (i, j) : (Int, Int) = "Hello" -> "World"
Вышеприведенное будет компилироваться и завершаться во время выполнения с помощью ClassCastException
. Легко забыть, что объявление (i, j)
является шаблоном.
EDIT: для ziggystar, правила назначения Scala утверждают, что в инструкции:
val p = expr //or var
p
может быть либо идентификатором, либо шаблоном (см. раздел раздела 15.7 программирования в Scala, стр. 284). Например, допустимо следующее:
val x :: y :: z :: rest = List(1, 2, 3, 4)
Принимая это вместе с тем, что шаблоны стираются (т.е. информация параметрического типа не отмечена) означает, что мой исходный пример будет скомпилирован.
Ответ 2
Из [ scala] Вопрос о соглашениях об именах вы можете прочитать
Начальная заглавная буква имеет преимущество при сопоставлении с образцом. Идентификаторы с начальной заглавной буквой считаются значениями для соответствия вместо переменной, подлежащей привязке.
Ответ 3
Обходной путь существует, если вам нужно инициализировать большое количество констант и вы хотите не писать val =
для каждого, или вы нажимаете ограничение размера кортежа (22).
Из раздела 4.1 Scala Спецификация языка:
Определение значения val x: T = e определяет x как имя значения, которое результаты оценки e. Определение значения val p1,..., pn = e - сокращенное обозначение последовательности значений val p1 = e;...; val pn = e.
В спецификации можно инициализировать последовательность значений с именами, начинающимися с заглавных букв, указав выражение справа, которое возвращает каждое значение в порядке.
val iter = Iterator(1, 2, 3)
val A, B, C = iter.next()
Другой пример:
val next = { var n = 0; () => { n = n + 1; n } }
val A, B, C, D, E, F, G, H = next()
В этих тривиальных случаях выше этот подход не очень полезен. Ниже приведен более полезный пример, который инициализирует константу для каждого из 64 квадратов шахматной доски (см. Square.scala#L31 для источника):
val squareIter = squares.iterator
val A1, A2, A3, A4, A5, A6, A7, A8,
B1, B2, B3, B4, B5, B6, B7, B8,
C1, C2, C3, C4, C5, C6, C7, C8,
D1, D2, D3, D4, D5, D6, D7, D8,
E1, E2, E3, E4, E5, E6, E7, E8,
F1, F2, F3, F4, F5, F6, F7, F8,
G1, G2, G3, G4, G5, G6, G7, G8,
H1, H2, H3, H4, H5, H6, H7, H8 = squareIter.next()