クロージャー。ラムダ式とかアローファンクションとか、そのへんと同じ仕組み。
iBooksを読んだメモです。
closureの基本形
{ ([parameters]) -> [return type] in
[statements]
}
{}
で囲み、その中に引数と戻り値を定義。そしてin
キーワードを挟んで処理の内容が続く。
iBooksの教科書ではsort
関数の引数に渡すサンプルが出てきてるので紹介。
// namesはString型の配列
reversed = sort(names, { (s1: String, s2: String) -> Bool in
return s1 > s2
})
ちなみにin
キーワードがあるおかげで改行はなくても問題なし。
closureの型推論
closureでもだいぶいい感じに型推論してくれるみたい。
実際に、上のsort
関数の場合は取る引数と返す値は自明なので、以下のように書ける。
reversed = sort(names, { s1, s2 in return s1 > s2 })
引数の型と()
、戻り値をばっさり省略した形。だいぶシンプル。
return
キーワードの省略
そしてさらに、式がひとつの場合(例だとs1 > s2
のみ)はさらにreturn
すらも省略可能。
reversed = sort(names, { s1, s2 in s1 > s2 })
徐々になにがなんだか分からなくなってきたw
ショートハンド引数名
さらにさらにさらに、インラインのclosureは引数名すら省略可能。
その場合は$0
、$1
、$2
・・・と先頭の引数から順にアクセスできる。
(余談だけど、JSのarguments[0]
とかで引数名なくてもアクセスできるのと同じと思う)
もちろん型推論される。
そしてショートハンドを使う場合はin
キーワードすら省略可能となる。
つまり、最初のsort
関数のclosureは以下のようにとてもシンプルに書ける。
reversed = sort(names, { $0 > $1 })
もはや関数なのか値なのかすら怪しい感じにw
オペレータ関数(Operator Functions)を使う
どうやらSwiftにはOperator Functionsという仕組みがあるみたい。
(これは別の機会に調査)
iBooksの教科書によれば、オペレータを定義して、その引数などを定義できるみたい。
要はオペレータのオーバーロードってことかな?
そしてString
型は<
や>
のオーバーロードをしていて、挙動がまさにsort
関数のそれと同じ。
・・なんとなく推測できると思うけど、つまり、最終的には以下のように書ける。
reversed = sort(names, >)
これ、知らないと第二引数まじ意味不明な気がするw
Trailing Closures
なんて訳していいか分からないのでそのままのタイトルw
(Trailing自体は末尾、みたいな意味)
「末尾」が表す通り、関数の引数の末尾(最後)がclosureを受け取る場合、処理部分を外に配置できる、というもの。
百聞は一見にしかずなので、実際のサンプルを見てもらうと分かると思う。
// 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
関数の外に処理が書かれていてなんでだろうって思っていたけど、どうやらこの仕組で書いているみたい。
こんな感じの↓
sort(arr) {
$0 > $1
}