Объявление нескольких переменных в 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

особенно если переменные имеют осмысленное имя.

Другие вопросы по тегам