我需要两个可以访问彼此私有的实例。我天生就想到了一个伴侣对象,它允许访问它的同伴类的唯一实例。这个类本身是私有的,因此用户不能只使用new
创建实例。
object A {
def apply = dual
lazy val dual = new A
}
private class A {
//some irrelevant logic...
}
此代码无法编译。我得到:类A逃避其定义范围作为类型A 错误的一部分,我真的不明白。我目前的解决方法是使用类应该具有的每个方法声明来定义特征,并使class A
扩展该特征,而 dual 属于特征类型,而不是class A
类型。
我在这里缺少什么理论问题?为什么这是禁止的?
答案 0 :(得分:29)
Paolo的解决方案很好(+1),但他没有解释错误信息,所以让我试一试。问题源于每个方法都需要返回类型的事实。您对apply
和dual
的原始定义返回了class A
的对象,因此两者的隐式返回类型为A
。这意味着客户必须能够看到A
- 他们如何调用该函数或访问val
?此外,由于两者 - 以及它们的父对象 - 都是公开的,因此它们是全局可见的。但是,您声明了A private
,这意味着它必须在其包外不可见。所以编译器无法解决冲突。
一般规则是函数/成员的所有参数和返回类型必须(至少)与引用成员本身*具有相同的可见性范围。因此,解决此问题的一个简单方法是降低apply
和dual
对private
的可见性。这将满足编译器,但不是你: - )
您的解决方案通过将静态返回类型更改为public
特征来解决问题,因此该特征与引用它的成员具有相同的可见性。返回对象的动态类型仍为class A
,但客户端无需显示此类型。这是原则"program to interfaces, not implementations"的典型例子。
请注意,要完全应用此原则,可以将class A
转换为private
的{{1}}内部类,从而使其即使对于同一个包中的其他类也无法访问:
object A
* 要迂腐,封闭的类/对象可能会降低其成员的可见性,如下所示:
trait A {
//...
}
object A {
def apply: A = dual
lazy val dual: A = new AImpl
private class AImpl extends A {
//some irrelevant logic...
}
}
其中private class Holder {
def member = new Hidden
}
private class Hidden
为member
但其封闭类为public
,有效地将其成员隐藏在外部世界中。所以编译器不会在这里发出任何抱怨。
答案 1 :(得分:24)
我认为你不需要私有类,而是需要私有构造函数的类。
class A private()
object A {
def apply = dual
lazy val dual = new A
}
现在,您的类对外部代码“可见”,但只有您的伴随对象才能创建它的实例。