【问题标题】:scala case class private apply method( repl bug ?)scala案例类私有应用方法(repl bug?)
【发布时间】:2013-02-12 11:20:38
【问题描述】:

在 Scala2.10.0 REPL 中

Welcome to Scala version 2.10.0 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_13).
Type in expressions to have them evaluated. 
Type :help for more information.

scala> case class A private(i:Int)
defined class A

scala> A(1)
res0: A = A(1)

但是如果编译

$ scala -version
Scala code runner version 2.10.0 -- Copyright 2002-2012, LAMP/EPFL
$ cat Main.scala 
package foo

case class A private (i:Int)

object Main extends App{
  println(A(1))
}

$ scalac Main.scala 
Main.scala:6: error: constructor A in class A cannot be accessed in object Main
  println(A(1))
          ^
one error found

A.apply(1) 是编译错误。

这是 Scala2.10.0 REPL 错误吗?

仅供参考 Scala2.9.2 REPL 正在关注

Welcome to Scala version 2.9.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_13).
Type in expressions to have them evaluated.
Type :help for more information.

scala> case class A private(i:Int)
defined class A

scala> A(1)
<console>:10: error: constructor A in class A cannot be accessed in object $iw
              A(1)
              ^

【问题讨论】:

    标签: scala constructor read-eval-print-loop case-class


    【解决方案1】:

    这绝对看起来像一个 REPL 错误。

    请注意,构造函数被正确标记为private(换句话说,new A(1) 没有按预期编译),只有工厂 (A.apply) 被错误地公开。

    【讨论】:

      【解决方案2】:

      我明白了...当您编写A(1) 时,您认为您正在调用构造函数。你不是。您正在调用自动​​生成的(公共)伴随对象及其公共apply 方法中为您添加的工厂。

      附录

      我的日子一再犯错……

      在 2.10.0 REPL 中:

      scala> object REPL { case class CC1 private(i: Int); val cc1_1 = CC1(23) }
      <console>:7: error: constructor CC1 in class CC1 cannot be accessed in object REPL
             object REPL { case class CC1 private(i: Int); val cc1_1 = CC1(23) }
      

      【讨论】:

      • 我不认为他将工厂与构造函数混合在一起,因为标题是“scala case class private apply method(repl bug ?)”。当我们真正尝试调用工厂时,实际上是 scala 编译器/REPL 令人困惑并谈论构造函数。
      • @RégisJean-Gilles:他做到了。只有在使用new关键字时才直接使用构造函数。
      • 我认为你没有抓住重点。这是一个案例类。使构造函数private 也应该使相应的工厂private。这正是你编译他的代码 sn-p 时发生的情况,但由于某种原因,REPL 中的行为有所不同。
      【解决方案3】:

      REPL 有一个巨大的语义差异 w.r.t。普通的编译器。

      考虑一下能够做到这一点意味着什么:

      scala> val v1 = 23
      v1: Int = 23
      
      scala> val v1 = 42
      v1: Int = 42
      

      你能在编译的 Scala 代码中这样做吗?当然不是,这将是一个被禁止的双重定义。

      REPL 如何做到这一点?实际上,您输入的每一行都在一个逐渐嵌套的范围内。重新定义的外观是实际的阴影。就好像你这样做了:

      object REPL1 {
        val v1 = 23
        object REPL2 {
          val v1 = 42
          object REPL3 {
            // Next REPL line here...
          }
        }
      }
      

      那么,你如何获得同伴?在它们周围放置一个显式对象(或其他范围形成结构)。请记住,没有空行。当你这样做时,REPL 将停止接受给定“行”或“块”的输入。

      【讨论】:

      • 你的意思是什么?这也无法在 REPL 之外编译为 Scala。
      • @Mef:哇...我完全没能通过使用v2 来表达我的观点!感谢您解决这个问题。
      • 我认为@Kenji Yoshida 的观点正是他模仿 REPL 所做的要点,也无法在 REPL 之外编译。或者换句话说,嵌套范围与他的问题无关。另外,你解释了如何在 REPL 中定义伴生对象,但他没有这样做:他的代码中只有一个 case 类,所以伴生对象实际上是自动生成的。最后一点,现在您可以在这种情况下使用:paste 命令。
      • 是的。我第一次回答错了问题。第二个答案是重点(尽管投反对票......)。
      猜你喜欢
      • 2020-05-16
      • 1970-01-01
      • 2019-01-18
      • 1970-01-01
      • 2017-06-23
      • 2013-12-30
      • 2018-12-10
      • 1970-01-01
      相关资源
      最近更新 更多