Closure
Swift

[Swift] Closureについてメモ

More than 1 year has passed since last update.

クロージャー。ラムダ式とかアローファンクションとか、そのへんと同じ仕組み。
iBooksを読んだメモです。

closureの基本形

closure1.swift
{ ([parameters]) -> [return type] in
    [statements]
}

{}で囲み、その中に引数と戻り値を定義。そしてinキーワードを挟んで処理の内容が続く。
iBooksの教科書ではsort関数の引数に渡すサンプルが出てきてるので紹介。

sort-sample.swift
// namesはString型の配列
reversed = sort(names, { (s1: String, s2: String) -> Bool in
    return s1 > s2
}) 

ちなみにinキーワードがあるおかげで改行はなくても問題なし。

closureの型推論

closureでもだいぶいい感じに型推論してくれるみたい。
実際に、上のsort関数の場合は取る引数と返す値は自明なので、以下のように書ける。

closure2.swift
reversed = sort(names, { s1, s2 in return s1 > s2 })

引数の型と()、戻り値をばっさり省略した形。だいぶシンプル。

returnキーワードの省略

そしてさらに、式がひとつの場合(例だとs1 > s2のみ)はさらにreturnすらも省略可能。

closure3.swift
reversed = sort(names, { s1, s2 in s1 > s2 })

徐々になにがなんだか分からなくなってきたw

ショートハンド引数名

さらにさらにさらに、インラインのclosureは引数名すら省略可能。
その場合は$0$1$2・・・と先頭の引数から順にアクセスできる。

(余談だけど、JSのarguments[0]とかで引数名なくてもアクセスできるのと同じと思う)

もちろん型推論される。
そしてショートハンドを使う場合はinキーワードすら省略可能となる。
つまり、最初のsort関数のclosureは以下のようにとてもシンプルに書ける。

closure3.swift
reversed = sort(names, { $0 > $1 })

もはや関数なのか値なのかすら怪しい感じにw

オペレータ関数(Operator Functions)を使う

どうやらSwiftにはOperator Functionsという仕組みがあるみたい。
(これは別の機会に調査)

iBooksの教科書によれば、オペレータを定義して、その引数などを定義できるみたい。
要はオペレータのオーバーロードってことかな?
そしてString型は<>のオーバーロードをしていて、挙動がまさにsort関数のそれと同じ。

・・なんとなく推測できると思うけど、つまり、最終的には以下のように書ける。

closure3.swift
reversed = sort(names, >)

これ、知らないと第二引数まじ意味不明な気がするw

Trailing Closures

なんて訳していいか分からないのでそのままのタイトルw
(Trailing自体は末尾、みたいな意味)

「末尾」が表す通り、関数の引数の末尾(最後)がclosureを受け取る場合、処理部分を外に配置できる、というもの。
百聞は一見にしかずなので、実際のサンプルを見てもらうと分かると思う。

trailing-closure.swift
// closureを受け取る関数の定義。
// 「(Int, Int) -> Int」という型の関数を受け取る
func add(a: Int, b: Int, closure: (Int, Int) -> Int) -> Int {
    return closure(a, b)
}

// addを普通に使う
add(1, 5, { (a: Int, b: Int) -> Int in
    return a + b
})

// Trailing版
// 実際の処理を引数の()の外に置いている
add(1, 5) {
    $0 + $1
}

本を読んでいて、たまにsort関数の外に処理が書かれていてなんでだろうって思っていたけど、どうやらこの仕組で書いているみたい。

こんな感じの↓

soft-trailing.swift
sort(arr) {
    $0 > $1
}