【问题标题】:Why can a companion object access a private val in its companion class when compiling, but cannot do that when interpreting?为什么伴生对象在编译时可以访问其伴生类中的私有 val,但在解释时不能这样做?
【发布时间】:2019-10-24 08:50:09
【问题描述】:
// Script A.scala
class A {
    private val privateVal = 1
}
object A extends App{ 
    println(new A().privateVal)
}

A.scala 可以毫无问题地编译和运行,因为伴随对象及其类可以访问彼此的私有成员。

$ scalac A.scala
$ scala A
1

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

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

【问题讨论】:

  • @SarveshKumarSingh 这是错误的。 “一般来说,类的伴生模块是一个与类同名的对象,定义在相同的作用域和编译单元中。”这就是所有需要的,扩展任何东西都没有问题。 scala-lang.org/files/archive/spec/2.13/…
  • @SarveshKumarSingh 我从未见过这样的要求。您提到的保证和限制是否有任何参考?
  • @AlexeyRomanov 我已经看到很多类似的不可预测性(在模式匹配中很常见)与“花式”伴随对象,只要伴随对象恢复为只是一个对象,它们就会消失。是的,没有提到伴生对象需要简单的任何地方,但您也不会在文档的任何地方找到“花哨”的伴生对象。
  • @SarveshKumarSingh 这真的需要一个“花式”的定义。当然,我认为集合类型的伴生对象比仅仅扩展 App 更有趣。
  • @AlexeyRomanov 不是真的...DelayedInit 更高级。无论如何,OP 的问题似乎已经解决,并且与此无关。

标签: scala read-eval-print-loop companion-object


【解决方案1】:

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

但是,当您在 Scala 中逐行解释代码时,它会将其包装在额外的匿名对象中,以允许在 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

【讨论】:

    【解决方案2】:

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

    $ scala
    scala> :paste A.scala
    

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

    amm A.scala
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-11-29
      • 1970-01-01
      相关资源
      最近更新 更多