Closure
Swift

[Swift] Closureについてメモ

More than 3 years have 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
}