Объявление нескольких переменных в Scala
Я хотел бы использовать 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
синтаксис разрешен?
5 ответов
Тривиальный ответ - объявить их кортежами:
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 уже есть сопоставление с образцом (общая особенность), которое можно использовать для обработки множественных назначений (используя трюк с кортежами, описанный в других ответах). Нет необходимости обрабатывать этот особый случай отдельно.
Немного отличаясь, стоит отметить, что синтаксис множественного присваивания в C (и, следовательно, в Java) также является частным случаем другой, более общей функции. Рассматривать:
int x = y = z = 1;
Это использует тот факт, что присваивание возвращает значение, назначенное в C-производных языках (а также тот факт, что присваивание является ассоциативным справа). Это не так в Скала. В Scala назначение возвращается Unit
, Хотя у этого есть некоторые раздражающие недостатки, это является более теоретически обоснованным, поскольку оно подчеркивает побочный эффект присваивания непосредственно в его типе.
Я добавлю одну причуду здесь, потому что она ударила себя и может помочь другим.
При использовании сопоставления с образцом, например, при объявлении нескольких переменных, не используйте заглавные имена для переменных. Они рассматриваются как имена классов в сопоставлении с образцом, и это также применимо и здесь.
val (A,B)= (10,20) // won't work
println(A)
Сообщение об ошибке на самом деле не говорит о том, что происходит:
src/xxx.scala:6: error: not found: value A val (A,B)= (10,20) ^ src/xxx.scala:6: error: not found: value B val (A,B)= (10,20) ^ src/xxx.scala:7: error: not found: value A println(A) ^
Я думал, что `-помощь решит проблему, но по некоторым причинам не кажется (не уверен, почему бы и нет):
val (`A`,`B`)= (10,20)
println(A)
Все те же ошибки, даже с этим.
Пожалуйста, прокомментируйте, если вы знаете, как использовать шаблон инициализации кортежа с именами заглавных переменных.
Если все ваши переменные имеют одинаковый тип и принимают одинаковое начальное значение, вы можете сделать это.
val a, b, c: Int = 0;
Кажется, это работает, если вы объявите их в кортеже
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
особенно если переменные имеют осмысленное имя.