这不能按预期工作(因为我尝试从外部run
调用包私有Services
):
object Services {
class HelloPrinter {
private[Services] def run = "Hello"
}
}
val obj = new Services.HelloPrinter
但令人惊讶的是,这有效:
val obj: {def run: String} = new Services.HelloPrinter
obj.run
我想说,它是编译器中的一个错误,因为HelloPrinter由于包可见性规则而与结构类型不匹配,所以它根本不应该编译!
以下是程序编译但会抛出运行时异常(java.lang.NoSuchMethodException
)的情况:
class HelloPrinter {
private[HelloPrinter] def run = "Hello"
}
val obj: {def run: String} = new HelloPrinter
obj.run
这是我缺少的语言功能或规则,还是Scala中的错误?
答案 0 :(得分:4)
在JVM级别上,不存在作用于周围实例/类型的可见性。在这种情况下,Scala编译器将生成一个公共方法,并在内部处理此可见性。
如果使用结构类型,编译器将反射访问此类型的成员。它不会检查Scala特定的可见性标志,而只检查Java字节码中定义的标志。
您没有提到您使用的是哪个版本的Scala编译器,但我认为这是您特定版本中的错误。尝试编译时,我得到与Jasper-M相同的结果。原因是编译器生成的方法实际上以类型名称为前缀,即在这种情况下为HelloPrinter$$run
。将执行以下代码:
val x: { def HelloPrinter$$run: String } = new HelloPrinter
x.run
Scala编译器再次生成一个公共方法并在内部管理可见性。它不是一个功能,而是一个错误,编译器不会检查结构类型的Scala内部可见性。