Paolo 的解决方案很好 (+1),但他没有解释错误信息,所以让我试试。问题源于每个方法都需要返回类型这一事实。您的原始定义apply
并dual
返回了一个对象class A
,因此两者的隐式返回类型都是A
。这意味着A
必须对客户可见——他们还能如何调用函数或访问val
? 此外,由于两者——以及它们的父对象——都是公共的,它们是全局可见的。但是,您声明A private
这意味着它不能在其包外可见。因此存在编译器无法解决的冲突。
一般规则是函数/成员的所有参数和返回类型必须(至少)与引用成员本身具有相同的可见性范围*。因此,解决此问题的一种简单方法是降低 和 的可见apply
性。这会满足编译器,但不是你:-)dual
private
您的解决方案通过将静态返回类型更改为public
特征来解决问题,因此与引用它的成员具有相同的可见性。返回对象的动态类型仍然是class A
,但是,这不需要对客户端可见。这是“程序到接口,而不是实现”原则的经典示例。
请注意,要完全应用此原则,可以class A
变成 的private
内部类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
where member
ispublic
但它的封闭类 is private
,有效地将其成员隐藏在外部世界之外。所以编译器在这里不会发出任何抱怨。