iBooks にある “The Swift Programming Language” の勉強メモ。Objective-C と C を普段書いている自分から、ちょっと馴染みがないものを特にまとめておきます。目次は こちら。
今回は、Closure に関して。
Closure
Closure は自己完結する機能のブロックです。 Closure は、C や Objective-C のブロック、他の言語ではラムダと似ているもの。グローバル関数とネストされた関数は、Closure の特殊なケースと考えることができます。
- ・グーバル関数は、名前を持ち、なんの値もキャプチャしない Closure。
- ・ネストされた関数は、名前を持ち、ネストしている関数の値をキャプチャしている Closure。
- ・Closure は、名前のない、文脈によって値をキャプチャしている、簡潔に書かれたもの。
Sort 関数は、引数に他の関数を取る関数です。この Sort 関数を例に、Closure についての説明をしていきます。
1. Closure とは
以前 の記事のネストされた関数も、大きな関数の中の一定のコードを整理するいい方法でしたが、より簡潔に書きたい場合があると思います。そのような場合に、Closure が使えます。
Sort 関数は、引数に配列と、Closure を取ります。この Closure は同じ型の引数を 2 つ取ります。そして、どちらの値が新しく返す配列の順番の中で先に来るかを Bool 型で返します。
1 2 3 4 5 6 7 8 | let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] func backwards(s1: String, s2: String) -> Bool { return s1 > s2 } var reversed = sort(names, backwards) // reversed is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"] |
この例では、Sort 関数の引数に関数を受け取っています。関数は、Closure の特殊なケースなので、関数を引数にすることができます。Closure を使用することで、この Sort 関数を実行するのにより効率的に、書くことができます。それを順にみていきます。
2. 基本的な Closure
まずは、コードです。
1 2 3 | reversed = sort(names, { (s1: String, s2: String) -> Bool in return s1 > s2 }) |
このコードは、先ほどの Sort 関数と全く同じ機能を持ちます。まず、{} 内の () にて、Closure の引数を指定します。そして、-> の後に返り値。in キーワードは、Closure の本体が始まるという意味です。ここでは、引数を比べて、その Bool を返すだけというシンプルなものです。これが基本的な Closure のシンタックスです。
3. Closure の型推論
この Sort Closure は、Sort 関数への引数として渡されています。したがって、Swift は、この引数の型を推論することがき、上記のコードをより簡潔に書くことができます。つまり、この Sort Closure の引数の型、返り値を省略し、下記のように書くことができます。
1 | reversed = sort(names, { s1, s2 in return s1 > s2 } ) |
Closure を関数の引数として渡す際には、いつでも Swift の型推論に頼ることができます。なので、めったに 2 のようなコードを書く必要はありません。
4. Closure 内での return 文の省略
Sort Closrure のような 1 文で完結するような Closure では、return 文さえも省略することができます。
1 | reversed = sort(names, { s1, s2 in s1 > s2 } ) |
この Closure は、本体に s1> s2 という 1 文しかなく、Bool を返すということは明らかです。したがって、return 文を省略できます。
5. 引数名の省略
このような inline closure に、Swift は自動的に引数の名前を用意してくれます。それらは、$0, $1, $2… と参照することができます。つまり、これを使えば、引数名さえも省くことができます。
1 | reversed = sort(names, { $0 > $1 } ) |
6. Operator Functions
Swift の String 型は、> オペレーターを 2 つの引数を取り、Bool を返す関数として実装しています。これを Operator Function というようです。これを利用すれば、Sort 関数をこのように書くことがきます。Operator Function は、別に解説されたページがあるようです。
1 | reversed = sort(names, >) |
最初の完全に定義された関数を引数にとっていた形と比べると、信じられないほど簡潔になりました。