为什么伴生对象在编译时可以访问其伴生 class 中的私有 val,但在解释时不能这样做?

Why can a companion object access a private val in its companion class when compiling, but cannot do that when interpreting?

// Script A.scala
class A {
    private val privateVal = 1
}
object A extends App{ 
    println(new A().privateVal)
}

A.scala 可以编译并且 运行 没有问题,因为伴随对象及其 class 可以访问彼此的私有成员。

$ scalac A.scala
$ scala A
1

为什么相同的代码在解释时会显示伴随对象无法访问其伴随对象 class 中的私有 val?

$ scala A.scala
error: value privateVal in class A cannot be accessed in A

要在 Scala 中获取伴生对象,class 必须在同一个文件中定义它的伴生对象。看起来这就是您正在做的事情,尤其是当您不使用解释器时。

然而,当您在 Scala 中逐行解释代码时,它会将其包装在额外的匿名对象中,以允许在没有显式 classes 或 REPL (more here) 中的对象的情况下定义表达式。

这是包装问题的说明:

无效:

$ scala
Welcome to Scala version 2.10.6 (OpenJDK 64-Bit Server VM, Java 1.8.0_222).
Type in expressions to have them evaluated.
Type :help for more information.

scala> class A {
     |     private val privateVal = 1
     | }
defined class A

scala> object A extends App{ 
     |     println(new A().privateVal)
     | }
<console>:9: error: value privateVal in class A cannot be accessed in A
           println(new A().privateVal)
                           ^

如果同时使用 :paste:

定义则有效
scala> :paste
// Entering paste mode (ctrl-D to finish)

// Script A.scala
class A {
    private val privateVal = 1
}
object A extends App{ 
    println(new A().privateVal)
}

// Exiting paste mode, now interpreting.

defined class A
defined module A

顺便说一句,我在 运行 scala A.scala 时没有遇到这个问题。也许我使用了不同的版本或设置。

如果您不能使用粘贴模式,或者不能让解释器一次读取整个文件,解决方法是将您的代码包装在任何对象中以强制解释单个代码块:

scala> object Workaround {
     | class A {
     |     private val privateVal = 1
     | }
     | object A extends App{ 
     |     println(new A().privateVal)
     | }
     | }
defined module Workaround

:paste命令也可以用于load the whole file,例如

$ scala
scala> :paste A.scala

还要考虑 ammonite,它似乎开箱即用

amm A.scala