パオロの解決策は良い(+1)ですが、彼はエラーメッセージを説明しなかったので、それを試してみましょう。この問題は、すべてのメソッドに戻り型が必要であるという事実に起因しています。の元の定義applyとdualオブジェクトを返したclass Aため、両方の暗黙の戻り型はでしたA。これAは、クライアントに表示される必要があることを意味します-他にどのように関数を呼び出したり、?にアクセスしたりできますvalか?さらに、両方(およびその親オブジェクトも)が公開されているため、グローバルに表示されます。ただし、A privateこれは、パッケージの外部に表示されてはならないことを意味することを宣言しました。そのため、コンパイラでは解決できない競合があります。
一般的な規則として、すべてのパラメーターと戻り値のタイプの関数/メンバーは、(少なくとも)参照メンバー自体と同じ範囲の可視性を持っている必要があります*。applyしたがって、この問題を解決する簡単な方法の1つは、との可視性を減らすこと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
はどこにmemberありますpublicが、それを囲むクラスはprivate、そのメンバーを外界から効果的に隠しています。したがって、コンパイラはここで苦情を出しません。