Scala 私有类的伴生对象:为什么不';这不是有效的吗?

Scala 私有类的伴生对象:为什么不';这不是有效的吗?,scala,types,companion-object,Scala,Types,Companion Object,我需要两个可以互相联系的例子。我自然而然地想到了一个同伴对象,它授予对其同伴类的唯一实例的访问权。我将类本身设置为私有,因此用户不能仅使用new创建实例 object A { def apply = dual lazy val dual = new A } private class A { //some irrelevant logic... } 此代码不可编译。我得到:类A作为类型A错误的一部分逃逸了它的定义范围,我真的不理解。我目前的解决方法是用类应该具有的每个

我需要两个可以互相联系的例子。我自然而然地想到了一个同伴对象,它授予对其同伴类的唯一实例的访问权。我将类本身设置为私有,因此用户不能仅使用
new
创建实例

object A {
    def apply = dual
    lazy val dual = new A
}

private class A {
    //some irrelevant logic...
}
此代码不可编译。我得到:类A作为类型A错误的一部分逃逸了它的定义范围,我真的不理解。我目前的解决方法是用类应该具有的每个方法声明定义一个trait,并使
class a
扩展该trait,而dual是trait类型,而不是
class a
类型


我这里缺少的理论问题是什么?为什么这是禁止的?

我想你不想要一个私有类,而是一个带有私有构造函数的类

class A private() 
object A {
    def apply = dual
    lazy val dual = new A
}
现在,您的类对外部代码是“可见”的,但只有您的同伴对象才能创建它的实例。

Paolo的解决方案很好(+1),但他没有解释错误消息,所以让我试试。问题源于这样一个事实:每个方法都需要一个返回类型。您对
apply
dual
的原始定义返回了
类A
的对象,因此这两个类的隐式返回类型都是
A
。这意味着
A
必须对客户端可见-否则他们如何调用函数或访问
val
?此外,由于两者(以及它们的父对象)都是公共的,因此它们是全局可见的。但是,您声明了一个私有的,这意味着它不能在包外可见。因此存在一个编译器无法解决的冲突

一般规则是,函数/成员的所有参数和返回类型必须(至少)具有与引用成员本身相同的可见性范围*。因此,解决此问题的一个简单方法是将
apply
dual
的可见性降低到
private
。这将使编译器满意,但您不满意:-)

通过将静态返回类型更改为
public
trait,您的解决方案可以绕过这个问题,因此它与引用它的成员具有相同的可见性。返回对象的动态类型仍然是
A类
,但是,这不需要对客户端可见。这是该原则的一个经典例子

请注意,为了充分应用这一原则,可以将
A类
转换为
对象A
私有
内部类,从而使同一包中的其他类也可以访问:

trait A {
    //...
}

object A {
    def apply: A = dual
    lazy val dual: A = new AImpl

    private class AImpl extends A {
        //some irrelevant logic...
    }

}
*为了迂腐,封闭的类/对象可能会降低其成员的可见性,如下所示:


其中
成员
公共的
,但其封闭类是
私有的
,有效地将其成员隐藏在外部世界之外。所以编译器在这里没有抱怨。

呵呵,互相交流privates@AK4749毕竟我们谈论的是她的同伴。这门课不允许任何人进入她的私人空间。。。虽然经过深思熟虑…谢谢!愚蠢的我。。。有时候,最令人费解的问题,其实有点愚蠢和简单。
private class Holder {
  def member = new Hidden
}

private class Hidden