Scala递归val行为

时间:2016-11-04 14:14:32

标签: scala scalac

你认为打印出来的是什么?

val foo: String = "foo" + foo
println(foo)

val foo2: Int = 3 + foo2
println(foo2)

答案:

foonull
3

为什么呢?规范中是否有一部分描述/解释了这一点?

编辑:为了澄清我的惊讶 - 我确实认识到foo val foo: String = "foo" + foo未定义,这就是为什么它有一个默认值null(整数为零)。但这看起来并不是很干净,而且我认为这里的意见与我一致。我希望编译器能阻止我做那样的事情。它在某些特定情况下确实有意义,例如在定义Stream本质上是懒惰的时候,但对于字符串和整数,我会期望由于重新分配给val或者告诉我我没有阻止我尝试使用未定义的值,就像我写val foo = whatever一样(假设whatever从未定义过)。

为了使事情进一步复杂化,@ dk14指出这种行为仅适​​用于表示为字段的值,并且不会在块内发生,例如

val bar: String = {
  val foo: String = "foo" + foo // error: forward reference extends...
  "bar"
}

4 个答案:

答案 0 :(得分:11)

是的,请参阅SLS Section 4.2

fooString,是参考类型。它的默认值为nullfoo2Int,其默认值为0.

在这两种情况下,您指的是尚未初始化的val,因此使用默认值。

答案 1 :(得分:1)

Scala的Int由下面的基本类型(int)支持,其默认值(在初始化之前)为0。

另一方面,StringObject,未初始化时确实为null

答案 2 :(得分:1)

在这两种情况下foo分别为foo2根据JVM规范具有默认值。对于引用类型,null0int Int,因为Scala会对其进行拼写。

答案 3 :(得分:1)

不幸的是,scala并不像Haskell那样安全,因为Java的OOP模型(“面向对象满足功能”)有所妥协。有一个安全的Scala子集Scalazzi,一些sbt / scalac-plugins可以给你更多的警告/错误:

https://github.com/puffnfresh/wartremoverdoesn't check代表你发现的情况)

回到你的情况,这只发生在表示为字段的值时,并且当你在函数/方法/块中时不会发生:

int main() {

string phrasesAndWords[6];

cin >> phrasesAndWords[0] >> phrasesAndWords[1] >> phrasesAndWords[2] >> phrasesAndWords[3] >> phrasesAndWords[4] >> phrasesAndWords[5]; // Recieve input

int counter = 0;

    while (counter < 6) {
    switch(phrasesAndWords[counter]) {

        case "RandomString":
            print("That sure was quite random. \n")
        default:
            print("I don't understaahnd... \n")
    };
    counter++;
};

这种情况的原因是与Java的集成scala> val foo2: Int = 3 + foo2 foo2: Int = 3 scala> {val foo2: Int = 3 + foo2 } <console>:14: error: forward reference extends over definition of value foo2 {val foo2: Int = 3 + foo2 } ^ scala> def method = {val a: Int = 3 + a} <console>:12: error: forward reference extends over definition of value a def method = {val a: Int = 3 + a} 编译到JVM中的val字段,因此Scala保存了JVM类的所有初始化细节(我相信它是JSR-133的一部分:Java记忆模型)。以下是解释此行为的更复杂的示例:

final

所以,在这里你可以看到你没有看到的警告。