web-dev-qa-db-ja.com

Swift "where"配列拡張

Swift 2.0の時点で、述語付きの状況に適用できる一般的な型の拡張に近づくことができるようです。

これはまだできませんが:

protocol Idable {
    var id : String { get }
}

extension Array where T : Idable {
    ...
}

...これを行うことができます:

extension Array {
    func filterWithId<T where T : Idable>(id : String) -> [T] {
    ...
    }
}

... and Swift文法的に受け入れます。しかし、私の人生では、例の関数の内容を記入するときにコンパイラーを幸せにする方法を理解することはできません。できるだけ明示的に:

extension Array {
    func filterWithId<T where T : Idable>(id : String) -> [T] {
        return self.filter { (item : T) -> Bool in
            return item.id == id
        }
    }
}

...コンパイラーは、フィルター処理のために提供されたクロージャーを受け入れません

タイプ '((T)-> Bool)'の引数リストで 'filter'を呼び出すことはできません

アイテムがIdableとして指定されている場合も同様です。誰もここで運がありましたか?

26
yo.ian.g
_extension Array {
    func filterWithId<T where T : Idable>(id : String) -> [T] {
    ...
    }
}
_

汎用メソッドfilterWithId()を定義します。汎用プレースホルダーTIdableに制限されています。しかし、その定義は、ローカルプレースホルダーTを導入します。これは、配列要素タイプTとは完全に無関係です(そしてメソッドのスコープ内でそれを隠します)。

したがって、配列要素がIdableに準拠する必要があることをnotに指定しているため、クロージャーを使用してself.filter() { ... }を呼び出すことはできません。要素はIdableであると想定しています。

Swift 2/Xcode 7 beta 2の場合、テンプレートでより制限的なジェネリック型で拡張メソッドを定義できます(比較 値によってオブジェクトを削除するための配列拡張) =非常に類似した問題の場合):

_extension Array where Element : Idable {

    func filterWithId(id : String) -> [Element] {
        return self.filter { (item) -> Bool in
            return item.id == id
        }
    }
}
_

または、プロトコル拡張メソッドを定義できます

_extension SequenceType where Generator.Element : Idable {

    func filterWithId(id : String) -> [Generator.Element] {
        return self.filter { (item) -> Bool in
            return item.id == id
        }
    }
}
_

シーケンス要素の型がSequenceTypeに適合する場合、filterWithId()Arrayに適合するすべての型(特にIdableに適合する)で利用可能です。

Swift 3では、これは

_extension Sequence where Iterator.Element : Idable {

    func filterWithId(id : String) -> [Iterator.Element] {
        return self.filter { (item) -> Bool in
            return item.id == id
        }
    }
}
_
44
Martin R