Swiftでの複数の型制約


133

私がこれらのプロトコルを持っているとしましょう:

protocol SomeProtocol {

}

protocol SomeOtherProtocol {

}

ここで、ジェネリック型を取る関数が必要だが、その型が準拠している必要がある場合は、次のようにするSomeProtocolことができます。

func someFunc<T: SomeProtocol>(arg: T) {
    // do stuff
}

しかし、複数のプロトコルに型制約を追加する方法はありますか?

func bothFunc<T: SomeProtocol | SomeOtherProtocol>(arg: T) {

}

同様のものはコンマを使用しますが、この場合、別の型の宣言を開始します。これが私が試したものです。

<T: SomeProtocol | SomeOtherProtocol>
<T: SomeProtocol , SomeOtherProtocol>
<T: SomeProtocol : SomeOtherProtocol>

スウィフトのドキュメントは、ジェネリック医薬品の章でこれを言及していないので、これは...特別に関連する質問です
ブルーノ・フィリップ

回答:


241

あなたは使用することができますwhere句あなたが(すべて満たさなければならないのを)したい、カンマで区切られたとして、あなたは多くの要件として指定することができます

スウィフト2:

func someFunc<T where T:SomeProtocol, T:SomeOtherProtocol>(arg: T) {
    // stuff
}

Swift 3&4:

func someFunc<T: SomeProtocol & SomeOtherProtocol>(arg: T) {
    // stuff
}

またはより強力なwhere句:

func someFunc<T>(arg: T) where T:SomeProtocol, T:SomeOtherProtocol{
    // stuff
}

もちろん、プロトコル構成(例:)を使用することもできますが、protocol<SomeProtocol, SomeOtherProtocol>柔軟性はやや劣ります。

を使用whereすると、複数のタイプが関係する場合に対処できます。

複数の場所で再利用するためにプロトコルを作成したり、作成したプロトコルに意味のある名前を付けたりすることもできます。

スウィフト5:

func someFunc(arg: SomeProtocol & SomeOtherProtocol) { 
    // stuff
}

プロトコルは議論の隣にあるため、これはより自然に感じられます。


これは論理的ではありませんが、私がこの1つに感謝するスパマーの1人になりたいことを知ってよかったです。私がそれを必要としてから1か月でこれに気づきませんでした。
Mathijs Segers、2015

3
型制約式のクラスと構造体で同じことをする方法はありますか?例えば<T where T:SomeStruct, T:AnotherStruct>?クラスの場合、コンパイラーはこれを「Tは両方のサブクラスである」と解釈しているように見え、構造体の場合は、それだけを報告し"Type 'T' constrained to non-protocol type"ます。
Jarrod Smith

OPの特定の例では、プロトコル構成望ましい方法である必要があります。上記の解決策は有効ですが、私見では、関数のシグネチャが不必要に散らかっています。また、たとえば型制約としてプロトコル構成を使用してもwhere、追加の型/その他の使用法、たとえばeg func someFunc<U, T: protocol<SomeProtocol, SomeOtherProtocol> where T.SubType == U>(arg: T, arg2: U) { ... }のtypealias SubTypeに句を使用できますSomeProtocol
dfri 2016

1
これはswift3で非推奨になり、使用することをお勧めします:func someFunc <T>(arg:T)where T:SomeProtocol、T:SomeOtherProtocol {
Cristi Băluță

2
Tが特定のオブジェクトタイプであり、特定のプロトコルを実装する必要があることを迅速に伝える方法はありますか?
Georg

73

次の2つの可能性があります。

  1. Jiaaroの回答に示されているwhere句を使用します。

    func someFunc<T where T : SomeProtocol, T : SomeOtherProtocol>(arg: T) {
        // do stuff
    }
  2. プロトコル構成タイプを使用します

    func someFunc<T : protocol<SomeProtocol, SomeOtherProtocol>>(arg: T) {
        // do stuff
    }

2
2番目のソリューションはよりきれいですが、私はこの答えに行きたいと思います。2つのオプションを提示することもより完全です
Mathijs Segers

2
番号2は、Swift 2でを宣言するときに機能する唯一のものですtypealias。ありがとう!
Bruno Philipe、2015年

19

Swift 3.0への進化はいくつかの変更をもたらします。2つの選択肢は少し異なります。

whereSwift 3.0で句を使用する:

where読みやすくするために、この句は関数シグネチャの最後に移動しました。したがって、複数のプロトコルの継承は次のようになります。

func someFunc<T>(arg: T) where T:SomeProtocol, T:SomeOtherProtocol {

}

protocol<>Swift 3.0 の構成を使用する:

protocol<>コンストラクトを使用した構成は廃止されています。以前protocol<SomeProtocol, SomeOtherProtocol>は次のようになります。

func someFunc<T:SomeProtocol & SomeOtherProtocol>(arg: T) {

}

参照。

の変更の詳細については、whereこちらをご覧くださいhttps : //github.com/apple/swift-evolution/blob/master/proposals/0081-move-where-expression.md

そして、protocol <>コンストラクトの変更の詳細はこちらです:https : //github.com/apple/swift-evolution/blob/master/proposals/0095-any-as-existential.md


13

Swift 3は、関数を宣言するための最大3つの異なる方法を提供します。

protocol SomeProtocol {
    /* ... */
}

protocol SomeOtherProtocol {
    /* ... */        
}

1. &演算子を使用する

func someFunc<T: SomeProtocol & SomeOtherProtocol>(arg: T) {
    /* ... */
}

2. where句を使用する

func someFunc<T>(arg: T) where T: SomeProtocol, T: SomeOtherProtocol {
    /* ... */
}

3. where句と&演算子の使用

func someFunc<T>(arg: T) where T: SomeProtocol & SomeOtherProtocol {
    /* ... */        
}

またtypealias、関数宣言を短縮するために使用できることにも注意してください。

typealias RequiredProtocols = SomeProtocol & SomeOtherProtocol

func someFunc<T: RequiredProtocols>(arg: T) {
    /* ... */   
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.