Скала присваивает вальс

Почему не возможно иметь это:

def main(args:Array[String]) {
    val whatever:String // Have it uninitialized here

    if(someCondition) {
        whatever = "final value" // Initialize it here
    }
}

Я не понимаю, почему это не должно быть законным. Я знаю, что могу сделать это var, но почему мы должны инициализировать val когда мы это объявим? Разве не кажется более логичным иметь возможность инициализировать его позже?

5 ответов

Ты можешь сделать:

  val whatever =
    if (someCondition)
      "final value"
    else
      "other value"

Решение Java на самом деле является обходным решением проблемы, когда не все выражения возвращают значения, поэтому вы не можете написать это на Java:

final String whatever = if (someCondition) {
    "final value"
} else {
    "other value"
}

Все чаще в Java все чаще используют троичный оператор:

final String whatever = someCondition ? "final value" : "other value"

Что хорошо для этого ограниченного варианта использования, но совершенно несостоятельно, когда вы начинаете работать с операторами switch и несколькими конструкторами.


Подход Скалы здесь другой. Вся конструкция объекта должна в конечном итоге проходить через один "первичный" конструктор, все выражения возвращают значение (даже если оно Unit, эквивалентный Java Void), и внедрение в конструктор сильно приветствуется. Это приводит к тому, что графы объектов создаются в виде ориентированного ациклического графа, а также очень хорошо работают с неизменяемыми объектами.

Вы также хотите знать, что объявление и определение переменных в отдельных операциях, как правило, является плохой практикой при работе с несколькими потоками и может сделать вас уязвимым для выставления нулей и условий гонки, когда вы меньше всего их ожидаете (хотя это не так). действительно проблема при строительстве объекта). Атомарное создание неизменных значений - это только один аспект того, как функциональные языки помогают справиться с параллелизмом.

Это также означает, что компилятор Scala может избежать некоторых ужасно сложных потоков анализа из спецификации языка Java.

Как уже говорилось, Scala Way ™ - это:

val whatever =
  if (someCondition)
    "final value"
  else
    "other value"

Подход, который также масштабируется до других структур управления:

val whatever = someCondition match {
  case 1 => "one"
  case 2 => "two"
  case 3 => "three"
  case _ => "other"
}

Приложив немного опыта Scala, вы обнаружите, что этот стиль помогает компилятору помочь вам, и вы должны сами писать программы с меньшим количеством ошибок!

Использование lazy valвот так:

def main(args:Array[String]) {
  lazy val whatever:String = if (someCondition) "final value" else "other value"

  // ...

  println(whatever) // will only initialize on first access
}

В дополнение к тому, что сказали другие, обратите внимание, что Java допускает "чистые конечные" "переменные", что мне очень не нравится:

final Boolean isItChristmasYet;

if (new Date().before(christmas)) {
    isItChristmasYet = Boolean.FALSE;
} else {
    isItChristmasYet = Boolean.TRUE;
}

Однако, благодаря анализу потока данных в компиляторе, javac не позволит вам оставить свой whatever переменная не назначена, если someCondition не держит

Потому что цель 'val' - сообщить читателю (и компилятору): "Это значение останется тем, к чему оно инициализировано, до тех пор, пока оно не прекратит свое существование"

Это не имеет большого смысла без инициализации.

Конечно, можно придумать что-то вроде val(3), который допускает три присваивания переменной, но я не думаю, что это будет полезно.

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