第一个是正确的 Scala 代码,但第二个甚至无法编译,这怎么可能?
能够编译的
object First {
class ABC(body: => Unit) {
val a = 1
val b = 2
println(body)
}
def main(args: Array[String]): Unit = {
val x = new ABC {
a + b
}
}
}
这个不能在 Scala 2.11 和 2.12 上编译
object Second {
class ABC(body: => Int) {
val a = 1
val b = 2
println(body)
}
def main(args: Array[String]): Unit = {
val x = new ABC {
a + b
}
}
}
最佳答案
这并不奇怪。让我们看第一个例子:
您声明您的类 ABC
来接收返回 Unit
的按名称传递参数,并且您认为以下代码段:
val x = new ABC {
a + b
}
正在传递 body
参数,它不是。真正发生的是:
val x = new ABC(()) { a + b }
如果您运行该代码,您将看到 println(body)
prints () 因为您没有传递 body
的值> 参数,编译器允许它编译,因为 scaladoc 声明只有 1 个 Unit
类型的值:
Unit is a subtype of scala.AnyVal. There is only one value of type Unit, (), and it is not represented by any object in the underlying runtime system. A method with return type Unit is analogous to a Java method which is declared void.
由于只有一个值,编译器允许您省略它,它将填补空白。单例对象不会发生这种情况,因为它们不扩展 AnyVal
。 Int
的默认值为 0
,Unit
的默认值为 ()
并且因为只有该值可用,编译器接受它。
来自documentation :
If ee has some value type and the expected type is Unit, ee is converted to the expected type by embedding it in the term { ee; () }.
单例对象不会扩展 AnyVal
,因此它们不会得到相同的对待。
当您使用如下语法时:
new ABC {
// Here comes code that gets executed after the constructor code.
// Code here can returns Unit by default because a constructor always
// returns the type it is constructing.
}
您只是向构造函数主体添加内容,而不是传递参数。
第二个示例无法编译,因为编译器无法推断 body: => Int
的默认值,因此您必须显式传递它。
结论
构造函数括号内的代码与传递参数不同。在相同的情况下,它可能看起来相同,但这是由于“魔法”。
关于scala - 使用惰性参数初始化类时 Scala 编译器的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45920873/