Scala分配vals

时间:2010-10-26 18:05:49

标签: scala immutability

为什么不能这样做:

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

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

我不明白为什么这不合法。我知道我可以将其设为var,但为什么我们必须在声明时准确初始化val?能够在以后初始化它似乎更合乎逻辑吗?

5 个答案:

答案 0 :(得分:38)

你可以这样做:

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

答案 1 :(得分:28)

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的一点经验,你会发现这种风格有助于编译器帮助你,你会发现自己编写的程序错误更少!

答案 2 :(得分:9)

像这样使用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
}

答案 3 :(得分:7)

除了其他人所说的,请注意Java允许“空白最终”“变量”,这是我有点想念的功能:

final Boolean isItChristmasYet;

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

但是,由于编译器中的数据流分析,如果whatever不成立,javac将不允许您取消分配someCondition变量。

答案 4 :(得分:3)

因为'val'的目的是向读者(和编译器)发出信号: “这个值将保持初始化状态,直到它不存在”

没有初始化,这没有多大意义。

当然,人们可以设想像val(3)那样允许对变量进行三次分配,但我不认为这会有多大用处。