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