web-dev-qa-db-ja.com

プロトコルに準拠した拡張機能に特定のアクセスレベルを設定できないのはなぜですか?

次のコード例があるとします。

_protocol MyProtocol {
    func someFunction()
}

public class MyClass {

}

public extension MyClass: MyProtocol {
    func someFunction() {
        print("hello")
    }
}
_

上記のコードをコンパイルすると、次のエラーが発生します。

エラー: 'public'修飾子は、プロトコルの適合を宣言する拡張機能では使用できません

拡張子をprivateとしてマークしても同じことが起こります。アクセスレベルの設定に関係なく、プロトコルに準拠した拡張機能のアクセスレベルを設定できないようです。プロトコル宣言をpublicまたはprivateに設定しても、エラーは削除されません。

質問

Swiftプロトコルに準拠している拡張機能のアクセスレベルをこのように制限する理由は何ですか?プロトコル準拠がクラスレベルで適用されている場合、そのような制限はありません。

コンパイラーに従ってprivate/publicの指定を削除すると、someFunction()のアクセスレベルはどうなりますか?

_extension MyClass: MyProtocol {
    func someFunction() {
        print("hello")
    }
}
_

この場合、元のMyClassの実装に従い、publicになると思いますが、よくわかりません。

拡張機能のプロトコル準拠はクラス全体がプロトコルに準拠することを意味し、拡張機能のアクセスレベルを再指定することは冗長であるため、この動作はありますか?

21
Paolo

これは、プロトコル自体のアクセスレベル以外のアクセスレベルではプロトコルに準拠できないためです。つまり、publicプロトコルを使用している場合、privateに準拠することはできません。これは、プロトコルの適合性が実行時に照会できるものであるため(したがって、現在のモジュール間で異なることはなく、異なるファイル/モジュールで2回実装されることもあり)、また、タイプは1つのファイルのプロトコルに準拠し、他のファイルで使用された場合、そのプロトコルに準拠しませんでした。

someFunctionのアクセスレベルの質問については、他の関数と同じルールに従います。つまり、型自体のアクセスレベルが低い場合を除き、デフォルトはinternalです。したがって、あなたの場合、MyClassMyProtocolが両方ともpublicである場合、someFunction()にもpublicをマークする必要があることを示すコンパイラエラーが表示されることが予想されます。ただし、MyProtocolは実際にはinternalのように見えるため、someFunction()のデフォルトはinternalになるため、アクセス修飾子を省略しても機能します。

18
Lily Ballard

プライベートな適合性は違反する可能性がありますLiskov Substitution Principle

Apple devloperフォーラムからの要約を同様の質問に返信して引用する:

「私がプライベートな適合について特に私が指摘した最大のことは、さらにサブクラス化されることを意図されたamonstクラスは、しばしば衝突する実装に終わることです。」

たとえば、プロトコルにプライベートに準拠し、そのすべてのメソッドを実装するクラスがあるとします。後でサブクラスがやって来て、同じことをしたいのですが、必要なメソッドを実装したいだけです(実装されていないオプションのものが、サブクラスが望むデフォルトの動作を提供する可能性があるためです)。しかし、今あなたは2つの問題を抱えています:

1)このプロトコルの実装を期待しているオブジェクトは、同じオブジェクト上でプロトコルの2つのコンシューマを持っている可能性があります。これにより、両方のオブジェクトが予期しない呼び出しから保護する必要があります。または、なし。プライベートな準拠のため、予期しない呼び出しを解決するためにサブクラスがスーパーを呼び出すことはできません。

2)スーパークラスの実装はその動作に影響を与えずに削除できないため、サブクラスがプロトコルを変更せずに必要な動作を取得する方法はありません。

出典: Apple Developer forum thread)へのリンク

2
Say2Manuj

コンパイラーに従ってプライベート/パブリック指定を削除すると、someFunction()?のアクセスレベルはどうなりますか?

あなたが言うことは何でも。 someFunction()のアクセスレベルをマークすることを妨げるものは何もありません。ただし、この場合、MyProtocolのアクセスレベルはprivateであるため、internalとしてマークすることはできません。

したがって、コードのデフォルトはinternalです。デフォルトではpublicはありません。 publicは常に明示的なオプトイン指定です。

1
matt