scala - 使用惰性参数初始化类时 Scala 编译器的奇怪行为

标签 scala lazy-initialization scala-compiler

第一个是正确的 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.

由于只有一个值,编译器允许您省略它,它将填补空白。单例对象不会发生这种情况,因为它们不扩展 AnyValInt 的默认值为 0Unit 的默认值为 () 并且因为只有该值可用,编译器接受它。

来自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/

相关文章:

scala - 我可以检查我的 Scala 代码库以查找 : "Comparing Unrelated types"? 类型的所有警告吗

scala - Scala 的类型删除如何用于更高种类的类型参数?

java - ClassLoader getResourceAsStream 未加载同一目录中的某些文件

Scala:有没有一种方法可以将类型别名视为不同于它们别名的类型?

Python 类成员延迟初始化

hibernate - hibernate 中的延迟初始化

Scala - 如何在运行时从外部文件编译代码?

scala - 在 Scala 中,当内部对象扩展封闭类时会发生什么?

scala - Apache Spark 根据列的不同值计算列值

mysql - Hibernate 多对多延迟初始化异常