为什么不能这样做:
def main(args:Array[String]) {
val whatever:String // Have it uninitialized here
if(someCondition) {
whatever = "final value" // Initialize it here
}
}
我不明白为什么这不合法。我知道我可以将其设为var
,但为什么我们必须在声明时准确初始化val
?能够在以后初始化它似乎更合乎逻辑吗?
答案 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)那样允许对变量进行三次分配,但我不认为这会有多大用处。