2017/11/10更新

[Swift] クロージャーの色々な書き方に慣れる

このエントリーをはてなブックマークに追加            

Swiftのクロージャー(Closures)は、書き方が独特でなかなか最初はとっつきづらいところ。今日はクロージャーの色々な書き方をブログに書きました。コードを真似して書いてみれば、きっとクロージャーに慣れると思うので、使ってみてください。



目次




サンプルコードとリファレンス

このブログで記載しているコードは、以下のオンラインデモで動くようにしています。
https://swift.sandbox.bluemix.net/#/repl/5a0255b1d0f9bc44a212103e

また、クロージャーについての公式ドキュメントは以下にあります。
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Closures.html

それぞれ適宜ご利用ください。



クロージャーの書き方

クロージャーとは処理のまとまりを表すもので、例えばJavascriptでは処理のコールバックなどでよく使われています。Swiftでもクロージャーを使うことができます。
今回は、以下の配列を逆順にソートする処理を、クロージャーを用いて実装したいと思います。
let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]


(クロージャーではなく)関数を渡す

クロージャーの記法を扱う前に、関数を渡して同様の処理を実現してみたいと思います。以下のように実装します。
// 2要素の大小比較をする関数
func backward(_ s1: String, _ s2: String) -> Bool {
    return s1 > s2
}

// ソート処理を引数に渡す.
var reversedNames = names.sorted(by: backward)

print(reversedNames)
// ["Ewa", "Daniella", "Chris", "Barry", "Alex"]
sortedby引数は「文字列を2つ受け取り比較結果をBoolで返す処理」を受け取るようになっていて、その形に合う関数を渡すことでソート処理を行うことができます。

これについて、以降ではクロージャーで実現したいと思います。


クロージャーの基本形

まずはクロージャーの基本的な書き方です。以下のような構文として定義されています。
// クロージャーの構文定義
{ (parameters) -> returnValue in
    statements
}
具体的に実装すると、以下のようになります。
// クロージャーの基本記法
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in 
    return s1 > s2
})
これが基本的な使い方です。書き方がちょっと独特で慣れづらいですが、省略せずに書くとこのようになります。

そしてSwiftのクロージャーは、この基本形を色々な形で省略することができます(その辺が初心者には難しいところ)。1つずつ見て行きたいと思います。


1行でクロージャーを書く場合

上記のクロージャーを1行で書くこともできます。
// 1行で書く.
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 })
また、1行で書く場合には、returnを省略することも可能です。
// returnを省略した
reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in s1 > s2 })
この辺りの挙動は、他の言語のクロージャーと似てますね。


型定義を省略する

クロージャーは、それを代入されるところ(今回の例だとsorted関数の引数)で、どのような形であるかがわかっているので、クロージャーから型定義(=引数の型と戻り値の定義)を省略することができます。
// 引数と戻り値の型定義を省略したバージョン
reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 })
また、1行でクロージャーを書く場合には、前述の通りreturnを省略することもできます。
// returnも省略した
reversedNames = names.sorted(by: { s1, s2 in s1 > s2 })
だいぶシンプルになってきましたね。この辺はよく使われる形かなと思います。


ショートハンド引数名(引数名の省略)

クロージャーの中では、(シェルの引数のように)$0$1などの変数で引数を参照することができます。それに合わせてクロージャー自体の引数の定義を省略することもできます。
// クロージャーの引数定義を省略し、$0と$1で引数にアクセス.
reversedNames = names.sorted(by: { $0 > $1 })
この書き方はシンプルですが、使いやすいかどうかは人次第と思います。


トレーリングクロージャー(Trailing Closures)

関数の引数の一番最後にクロージャーが定義される場合、以下のような特別な記法で実装することができます。
// トレーリングクロージャー
reversedNames = names.sorted() { $0 > $1 }
一旦関数を()で閉じて、その後にクロージャーを書く感じです。僕はSwiftを始めて最初はこの書き方の意味がわかりませんでした・・・(泣)。

さらに、関数の引数にクロージャーが1つのみ定義されている場合には、()自体も省略することができます。
reversedNames = names.sorted { $0 > $1 }
とてもシンプルですが、なかなかクセの強い書き方です。トレーリングクロージャーの記法はよく使われるので、慣れて行きたいところです。


(参考)オペレータ関数の利用

今回のsortedで文字列の並び替えをする場合、文字列で定義されている比較演算子(>など)は、Swiftではメソッドとして実装されているため、以下のような呼び出しも可能です。
reversedNames = names.sorted(by: >)
Swiftの言語仕様を知らないと、これだけ見たらなんのこっちゃわかりませんが、知っておくと良いと思います。



最後に

Swiftのクロージャーについて、このブログを書くまでは頭の中が混乱していましたが、書き出してみるととってもスッキリしました。ぜひ一度手を動かして書いてみることをお勧めします。

本ブログでは、Swift、Go言語、Python、フロントエンド、Linux、Node.js、インフラ、Java、機械学習、などの技術トピックを発信をしていきます。「プログラミングで困ったその時に、解決の糸口を見つけられる」そんな目標でブログを書き続けています。今後も役立つネタを書いていきますので、ぜひ本ブログのRSSTwitterをフォローして貰えたら嬉しいです ^ ^

最後までご覧頂きましてありがとうございました!





こんな記事もいかがですか?

RSS画像

もしご興味をお持ち頂けましたら、ぜひRSSへの登録をお願い致します。