Я хотел бы использовать val
объявить несколько переменная как это:
val a = 1, b = 2, c = 3
Но по любой причине, это - синтаксическая ошибка, таким образом, я закончил тем, что использовал также:
val a = 1
val b = 2
val c = 3
или
val a = 1; val b = 2; val c = 3;
Я лично нахожу обе опции чрезмерно подробными и довольно ужасными.
Существует ли более оптимальный вариант?
Кроме того, я знаю, что Scala является очень хорошо продуманным языком, итак, почему не val a = 1, b = 2, c = 3
синтаксис позволяется?
Тривиальный ответ - объявить их кортежами:
val (a, b, c) = (1, 2, 3)
Здесь может быть интересно то, что это основано на совпадении паттернов. На самом деле происходит то, что вы строите кортеж, а затем, через выравнивание по образцу, присваиваете значения a
, b
и c
.
Давайте рассмотрим другие примеры выравнивания по образцу, чтобы исследовать это немного подробнее:
val DatePattern = """(\d{4})-(\d\d)-(\d\d)""".r
val DatePattern(year, month, day) = "2009-12-30"
val List(rnd1, rnd2, rnd3) = List.fill(3)(scala.util.Random.nextInt(100))
val head :: tail = List.range(1, 10)
object ToInt {
def unapply(s: String) = try {
Some(s.toInt)
} catch {
case _ => None
}
}
val DatePattern(ToInt(year), ToInt(month), ToInt(day)) = "2010-01-01"
В качестве примера, в частности, rnd
может быть написан более простой пример, без иллюстрации выравнивания по образцу, как показано ниже.
val rnd1, rnd2, rnd3 = scala.util.Random.nextInt(100)
Ответ Дэниела прекрасно суммирует правильный путь, а также почему он работает. Так как он уже охватил этот аспект, я постараюсь ответить на более широкий вопрос (относительно языкового дизайна)...
Там, где это возможно, Scala старается избегать добавления особенностей языка в пользу обработки вещей с помощью существующих механизмов. Например, Scala не включает утверждение break
. Однако, почти тривиально откатить один из своих в качестве библиотеки:
case object BreakException extends RuntimeException
def break = throw BreakException
def breakable(body: =>Unit) = try {
body
} catch {
case BreakException => ()
}
Это можно использовать следующим образом:
breakable {
while (true) {
if (atTheEnd) {
break
}
// do something normally
}
}
(примечание: это включено в стандартную библиотеку для Scala 2.8)
Многочисленные синтаксисы присваивания, например, такие языки как Ruby (например, x = 1, y = 2, z = 3
), попадают в категорию "избыточного синтаксиса". Если в Scala уже есть функция, которая включает определенный шаблон, она избегает добавления новой функции только для того, чтобы справиться с особым случаем этого шаблона. В этом случае, в Scala уже есть совпадение по шаблону (общая особенность), которое может быть использовано для обработки многократного назначения (с помощью трюка с кортежом, описанного в других ответах). В этом случае, Scala уже имеет совпадение паттернов (общий признак), которое может быть использовано для обработки множественных назначений (используя фокус с кортежом, описанный в других ответах). Нет необходимости работать с этим особым случаем отдельным образом.
С небольшим отличием, стоит отметить, что синтаксис множественного назначения на C (и, таким образом, Java) также является особым случаем другого, более общего признака. Рассмотрим:
int x = y = z = 1;
В этом случае используется тот факт, что присваивание возвращает значение, назначенное в Си-деривативных языках (а также тот факт, что присваивание является право-ассоциативным). В языке Scala это не так. В языке Scala присваивание возвращает Единица измерения
. Хотя это и имеет некоторые досадные недостатки, но теоретически оно более корректно, так как подчеркивает побочную природу присваивания непосредственно в его типе.
Похоже, что это сработает, если вы объявите их в кортеже
scala> val (y, z, e) = (1, 2, 45)
y: Int = 1
z: Int = 2
e: Int = 45
scala> e
res1: Int = 45
, хотя я, вероятно, пойду на отдельные заявления. Для меня это выглядит яснее:
val y = 1
val z = 2
val e = 45
особенно, если переменные имеют значимые имена.