类/对象初始化斯卡拉奇怪的行为[副本](Scala strange behavior in clas

2019-08-03 02:26发布

可能重复:
Scala和向前引用

是否有任何理由为什么在斯卡拉以下工作:

第1版

object Strange extends App {
  val x = 42
  Console.println(x) // => outputs "42", as expected
}

第2版

object Strange extends App {
  Console.println(x) // => "0" ?!
  val x = 42
}

为什么它编译于一切,为什么没有任何警告或任何行为如此怪异?

它也具有相同的问题class

class StrangeClass {
  Console.println(x) // => still "0"
  val x = 42
}

object TestApp extends App {
  new StrangeClass()
}

有与普通方法的身体没有这样的问题:

def nonStrangeMethod {
  Console.println(y) // => fails with "not found: value y", as expected
  y = 42
}

和行为发生巨大变化,如果我们想补充“最后”为val声明:

class StrangeClass {
  Console.println(x) // => "42", but at least that's expected
  final val x = 42
}

为了记录,下面的Java静态(Scala的object )对口:

public class Strange {
    static {
        System.out.println(x);
    }
    static int x = 42;

    public static void main(String[] args) {}
}

失败的编译与平原和理解错误“无法引用之前它被定义字段,”上线3#和Java非静态(Scala的class )对口:

public class Strange {
    Strange() {
        System.out.println(x);
        int x = 42;
    }

    public static void main(String[] args) {
        new Strange();
    }
}

显然失败,“×不能被解析为一个变量”上线#3。

Answer 1:

这是因为的App ,其使用延迟初始化特质。 从Scala中关于编程 App特点:

大括号之间的代码被收集到singleton对象的主构造,并且当所述类被初始化时执行

在2.9.0版本说明本太:

对象继承的应用特点,而不是利用斯卡拉2.9的延迟初始化功能来执行整个身体作为一个继承的主要方法的一部分。

所以Console.println(x)不执行,直到Strange是跑到你在哪里得到这样的输出:

scala> s.main(Array[String]())
0

如果添加另一个Console.println(x)val x = 42 ,然后它打印出来:

scala> s.main(Array[String]())
0
42

编译器知道x在当前范围存在,但直到它被执行它延缓了它的评价,然后打印出默认值Int0



Answer 2:

答案基本上是编译器如何构造的东西。 由于在斯卡拉静态变量 - 初始化主要发生在构造函数中,因此Java相当于你的第二个例子是相似的:

public class Strange {
    int x = 0;

    public Strange() {
        System.out.println(x);
        x = 42;
    }
}

这将汇编的罚款。 我假定编译器设置了未初始化的int为0的值,以避免NPE。 如果您在构造反转语句的顺序,你会得到你描述的第一个例子中的行为。

目前在这个问题上的一些更详细: Scala和向前引用



文章来源: Scala strange behavior in class/object initialization [duplicate]