Объявление нескольких переменных в 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
?
Ответы
Ответ 1
Тривиальный ответ - объявить их как кортежи:
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)
Ответ 2
Даниэль отвечает красиво подытоживает правильный способ сделать это, а также почему он работает. Поскольку он уже покрыл этот угол, я попытаюсь ответить на ваш более широкий вопрос (относительно языка)...
По возможности, 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. В Scala присваивание возвращает Unit
. Хотя у этого есть некоторые неприятные недостатки, он более теоретически обоснован, поскольку он подчеркивает побочный эффект присваивания непосредственно в его типе.
Ответ 3
Я добавлю здесь одну причуду, потому что она ударила меня и могла помочь другим.
При использовании сопоставления образцов, s.a. в объявлении нескольких переменных, не используйте имена Capital для переменных. Они рассматриваются как имена классов в сопоставлении с образцом, и оно также применяется здесь.
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)
Все те же ошибки даже при этом.
Прокомментируйте, если вы знаете, как использовать шаблон инициализации кортежа с именами переменных капитала.
Ответ 4
Кажется, что это работает, если вы объявите их в кортеже
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
особенно если переменные значимо названы.
Ответ 5
Если все ваши переменные одного типа и принимают одинаковое начальное значение, вы можете сделать это.
val a, b, c: Int = 0;