3

デフォルトのパラメーターを持つ静的メソッドを持つプロトコルがあります。プロトコルを実装するクラスのデフォルト値を変更したい。クラスやスーパーで簡単にできることを本質的にやっています。
プロトコルに関連付けられたタイプがない場合にのみ解決策があります。

次のコードは機能しますが、関連する型宣言のコメントを外すとすぐにコンパイルされません。

protocol Protocol {
//    associatedtype AssociatedType
}

extension Protocol {
    func sayHello(name: String = "World") {
        print("Hello, \(name)!")
    }
}

class Class<T>: Protocol {
    typealias AssociatedType = T

    func sayHello(name: String = "Stack Overflow") {
        // Uncommenting the Protocol.AssociatedType causes:
        // Protocol can only be used as a generic constraint because it has associated type requirements
        (self as Protocol).sayHello(name)
    }
}

Class<()>().sayHello()

コンパイルされない理由は理解できます:Protocolの具体的な型がありませんAssociatedType
したがって、質問は「プロトコルを明示的に特化できますか?」と読むべきかもしれませんが、それに対する答えはノーだと思います。

部分的な回避策があります。しかし、それが機能するときでさえ、それはひどいです。
特に、公開されているライブラリを作成していると考えるとsayHello、次の回避策により、公開する必要があるが役に立たない2番目のプロトコルを作成する必要があります。
回避策は次のとおりです。

protocol Parent {}

protocol Protocol: Parent {
    associatedtype AssociatedType
}

extension Parent {
    func sayHello(name: String = "World") {
        print("Hello, \(name)!")
    }
}

class Class<T>: Protocol {
    typealias AssociatedType = T

    func sayHello(name: String = "Stack Overflow") {
        (self as Parent).sayHello(name)
    }
}

Class<()>().sayHello()

しかし、私sayHelloは関連付けられた型を使用しているため、これはうまくいきません。したがって、別のプロトコルに抽出することはできません。

私が明確であることを確認するために、ここに私が望むものがあります。プロトコルのクラスを置き換えるだけです:

class Protocol<T> {
    func sayHello(name: String = "World") {
        print("Hello, \(name)!")
    }
}

class Class<T>: Protocol<T> {
    override func sayHello(name: String = "Stack Overflow") {
        super.sayHello(name)
    }
}

Class<()>().sayHello()
4

2 に答える 2

4

あなたはプロトコルの継承を再発明しようとしていますが、そのようなことはありません。しかし、あなたが話していることを理解するのは簡単です。言いたいことを言ってください。「受け継いだものをやりたい」という意味ではありません。あなたは「私はいくつかの一般的な行動をしたい」という意味です。その一般的な動作に名前を付けるだけです。これにより、どちらを意味するかについてのあいまいさがすべてなくなります。

protocol Protocol {
        associatedtype AssociatedType
}

extension Protocol {
    // Put the default behavior on the protocol, not on the instance
    // Of course you could also put it on the instance if that were convenient.
    static func defaultSayHello(_ name: String = "World") {
        print("Hello, \(name)!")
    }

    // If you want a default on the instance, too, provide one that we an override
    func sayHello(_ name: String = "World") {
        Self.defaultSayHello(name)
    }
}

class Class<T>: Protocol {
    typealias AssociatedType = T

    func sayHello(name: String = "Stack Overflow") {
        // Now the default behavior lives on my type
        Class.defaultSayHello(name)
    }
}

// But other types can get default behavior
class OtherClass<T>: Protocol {
    typealias AssociatedType = T
}

Class<()>().sayHello() // Hello, Stack Overflow!
OtherClass<()>().sayHello() // Hello, World!

defaultSayHelloこれに関する 1 つの苛立たしい部分は、Swift が の実装者に制限する方法を提供しないことですProtocol。したがって、技術的には誰でも呼び出すことができます。_部外者がすべきでないことを示すために、接頭辞を付ける価値がある場合があります。これはプロトコルにおける基本的なアクセス制御の問題であり、この特定の質問とは何の関係もありません。「私の実装者が自分で使用できるが、ランダムに呼び出されるべきではないもの」が必要なときに常に出てきます。現在、Swift にはそのための解決策がありません。

于 2016-08-27T18:15:23.967 に答える