Назначьте сразу несколько переменных в scala
У меня есть следующий код:
val text = "some text goes here"
val (first, rest) = text.splitAt(4)
println(first + " *" + rest)
Это прекрасно работает.
Однако, я хочу иметь два случая, определяющих "первый" и "отдых" снаружи, например:
val text = "some text goes here"
var (first, rest) = ("", "")
if (text.contains("z")) {
(first, rest) = text.splitAt(4)
} else {
(first, rest) = text.splitAt(7)
}
println(first + " *" + rest)
Но это дает мне ошибку:
scala> | <console>:2: error: ';' expected but '=' found.
(first, rest) = text.splitAt(4)
Почему это ошибка (сначала, rest) = text.splitAt(4), но не делать val (first, rest) = text.splitAt(4)? И что я могу сделать?
Изменить: не может повторно назначить значение val, изменено на var. Такая же ошибка
Ответы
Ответ 1
Ответ Serj дает лучший способ написать это, но для ответа на ваш вопрос о том, почему ваша вторая версия не работает, вы можете перейти к Scala, что делает различие между определениями переменных и назначениями.
Из "4.2. Объявления и определения переменных":
Переменные определения могут альтернативно иметь шаблон (§8.1) как левая сторона. Определение переменной var p = e
, где p
является шаблон, отличный от простого имени или имени, за которым следует двоеточие, и тип расширяется таким же образом (§4.1) в качестве определения значения val p
= e
, за исключением того, что свободные имена в p
вводятся как изменяемые переменные, а не значения.
Из "6.15 Назначения":
Интерпретация присваивания простой переменной x = e
зависит от по определению x
. Если x
обозначает изменяемую переменную, то присваивание изменяет текущее значение x
как результат оценивая выражение e
.
(first, rest)
Вот шаблон, а не простая переменная, поэтому он работает в определении переменной, но не в присваивании.
Ответ 2
Прежде всего val
является неизменным, поэтому вы не можете переназначить его. Во-вторых, if
, как и все структуры управления в Scala, может вернуть значение. Итак, вы можете сделать это следующим образом:
val text = "some text goes here"
val (first, rest) = if (text.contains("z")) text.splitAt(4) else text.splitAt(7)
println(first + " *" + rest)
Ответ 3
Ответ SerJ de SuDDeN абсолютно прав, но некоторые подробности, почему код, который вы упомянули, работает так, как он работает.
val (a, b) = (1, 2)
называется экстрактором образца-совпадения-выражения. Значение с правой стороны сопоставляется с экстрактором левой стороны. Это можно сделать везде в Scala и иметь разные грани. Например, соответствие шаблона в списке может выглядеть примерно так:
scala> val head :: tail = 1 :: 2 :: 3 :: Nil
head: Int = 1
tail: List[Int] = List(2, 3)
С правой стороны символ ::
-symbol - это метод класса List, который добавляет к нему элементы. С левой стороны ::
-символ является экстрактором класса ::
, подкласса List.
Некоторые другие места могут быть понятными
scala> for ((a, b) <- (1 to 3) zip (4 to 6)) println(a+b)
5
7
9
или эквивалентная нотация с помощью методов более высокого порядка
scala> (1 to 3) zip (4 to 6) foreach { case (a, b) => println(a+b) }
5
7
9