1. ホーム

[解決済み】Swiftで型付き配列を拡張するにはどうすればいいですか?

2022-04-17 16:14:26

質問

どうすればSwiftの Array<T> または T[] をカスタム機能ユーティリティで作成することはできますか?

Swift の API ドキュメントをブラウズすると、Array メソッドが T[] などがあります。

extension T[] : ArrayType {
    //...
    init()

    var count: Int { get }

    var capacity: Int { get }

    var isEmpty: Bool { get }

    func copy() -> T[]
}

同じソースをコピー&ペーストして、こんなバリエーションを試した場合。

extension T[] : ArrayType {
    func foo(){}
}

extension T[] {
    func foo(){}
}

というエラーが出てビルドに失敗します。

名目上の型 T[] 拡張できない

完全な型定義を使用すると、次のように失敗します。 Use of undefined type 'T' は、すなわち

extension Array<T> {
    func foo(){}
}

また、次のようにしても失敗します。 Array<T : Any>Array<String> .

不思議なことに、Swiftは型付きでない配列を拡張することができます。

extension Array {
    func each(fn: (Any) -> ()) {
        for i in self {
            fn(i)
        }
    }
}

で呼び出すことができます。

[1,2,3].each(println)

しかし、メソッドを通過する際に型が失われるようで、適切な汎用型拡張を作成することができません。 Swift の組み込みフィルタを :

extension Array {
    func find<T>(fn: (T) -> Bool) -> T[] {
        var to = T[]()
        for x in self {
            let t = x as T
            if fn(t) {
                to += t
            }
        }
        return to
    }
}

しかし、コンパイラはこれを型付けされていないものとして扱い、拡張子を呼び出すことを許可します。

["A","B","C"].find { $0 > "A" }

そして、デバッガでステップスルーすると、その型が Swift.String にキャストせずに String のようにアクセスしようとすると、ビルドエラーになります。 String 最初に、つまり

["A","B","C"].find { ($0 as String).compare("A") > 0 }

組み込みの拡張機能のように動作する型付き拡張メソッドを作成する適切な方法をご存知の方はいらっしゃいますか?

どのように解決するのですか?

型付き配列を拡張するために クラス の場合、以下のようにするとうまくいきます(Swift 2.2 ). 例えば、型付き配列をソートする場合。

class HighScoreEntry {
    let score:Int
}

extension Array where Element == HighScoreEntry {
    func sort() -> [HighScoreEntry] {
      return sort { $0.score < $1.score }
    }
}

でやってみる。 構造体 または タイプエイリアス はエラーになります。

Type 'Element' constrained to a non-protocol type 'HighScoreEntry'

更新情報 :

型付き配列を拡張するために 非クラス は、次のような方法をとります。

typealias HighScoreEntry = (Int)

extension SequenceType where Generator.Element == HighScoreEntry {
    func sort() -> [HighScoreEntry] {
      return sort { $0 < $1 }
    }
}

スウィフト3 の一部の型は名前が変更されました。

extension Sequence where Iterator.Element == HighScoreEntry 
{
    // ...
}