[Swift 3.1] extensionでジェネリックパラメーターと具象型が等しい制約が書けるようになりました

2017.03.29

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

特定の型を要素に持つArrayにプロパティやメソッドを追加したい

「特定の型を要素に持つArrayにプロパティやメソッドを追加したい」というケースがあると思います。
例えば、要素がInt型のArrayに対して合計値を取得するtotalというプロパティを追加するケースを考えます。

Swift 3.1

Swift 3.1では以下のようにジェネリックパラメーターと具象型が等しいという制約が書けるようになりました!

extension Array where Element == Int {
    var total: Element {
        return reduce(0, +)
    }
}
let intArray = [1, 2, 3, 4, 5]
print(intArray.total) // 15

Swift 3.1以前

これまではextension Array where Element == Int {}のように書こうとすると以下のエラーとなっていました。

Same-type requirement makes generic parameter 'Element' non-generic

ジェネリックパラメーターに対する制約はプロトコルでなければならなかったため、そのためにわざわざプロトコルを定義しなければいけませんでした。
微妙ですね...

protocol IntProvider {
    var int: Int { get }
}

extension Int: IntProvider {
    var int: Int {
        return self
    }
}

extension Array where Element: IntProvider {
    var total: IntProvider {
        var t = 0
        forEach { e in t += e.int }
        return t
    }
}

Optionalにも使える

もちろんOptional型にも使うことが可能です。 以下のようにString?型のみ拡張することが可能です。

extension Optional where Wrapped == String {
    // String?型のみ拡張できる!
}

まとめ

Swift 3.1での変更点の中でも「これは良い!」と思う変更でした。
ぜひ積極的に使っていきたいです。

参考資料