パオロの解決策は良い(+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
、そのメンバーを外界から効果的に隠しています。したがって、コンパイラはここで苦情を出しません。