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