mapに渡せるのはクロージャだけではない

map()では、transform引数にクロージャを渡します。たとえばInt型の配列を文字列化する処理を考えた場合、次のように書けます。

let foo = [1,2,3,4,5,6].map{ String($0) } // ["1", "2", "3", "4", "5", "6"]

ですが、このような初期化を伴う処理は次のようにも書けます。

let bar = [1,2,3,4,5,6].map(String.init) // 同じく["1", "2", "3", "4", "5", "6"]

このinit()StringInterpolationConvertibleプロトコルメソッドです。特殊なものではありません。

extension String : StringInterpolationConvertible {
    /// Create an instance containing `expr`'s `print` representation.
     : // 中略
    public init(stringInterpolationSegment expr: Int)
}

この書き方のポイントは、map()の引数にラムダでなく、カッコの付いたinit()でもなく、initと関数自体を渡しているところです。それにより配列の要素がinitにそのまま渡っていき、そこで返した値がmap()の戻りになるという寸法です。

図にしてみましょう。map{ String($0) }が前者で、map(String.init)が後者です。

f:id:swiftlife:20151227234959p:plain f:id:swiftlife:20151227235021p:plain

クロージャを介さず処理を渡せるので、余分な処理も減っていることが見て取れます。

もちろん、initに限らず私たちが作成した関数も利用できます。

func f(i:Int) -> String {
    return String(i*2)
}
let foo = [1,2,3,4,5,6].map(f) // ["2", "4", "6", "8", "10", "12"]

上手に利用したいものですね。