##はじめに
Swiftのクロージャは多くの初心者がつまづくところだと思います。自分自身もクロージャの書き方が分かっても、「これはどういう場面で使うんだ?」、とか「使う必要ある?」などと思いました。
そもそもクロージャというのは、コードを少なくするためだったり、高い表現力を実現するツールなので、書き方だけを説明されても使う場面が思い浮かびません。そこでこの記事ではクロージャを使う流れを簡単に説明して、「こんな時にクロージャを使うのか!」というのを感じてもらえたら嬉しいです。
最初はクロージャは使いませんが、後半で出てきます。
##まず関数を作る
これはn1とn2という入力値に対して(n1 + n2)をかえすという、ごく普通の関数です。
ここでcalculator関数は、足し算を計算してくれる計算機と言えます。
func calculator(n1: Int, n2: Int) -> Int {
return n1 + n2
}
calculator(n1: 3, n2: 2) //=> 5
これを掛け算を計算する計算機にするには、このように出力の部分を変えればいいですよね。
func calculator(n1: Int, n2: Int) -> Int {
return n1 * n2
}
calculator(n1: 3, n2: 2) //=> 5
しかしこの計算機は今、足し算か掛け算のどちらかしか計算できない、ちょっと使えない計算機です。そこでこの計算機に、足し算をしたいときは「足し算をしてください」、掛け算をしたいときは「掛け算をしてください」とお願いをすることで、足し算と掛け算を使い分けられるようにします。
その方法というのが、先ほど作ったcalculation関数の引数に関数を設定するという方法です。
##関数の引数に関数を設定する
関数という言葉が二回出てきてちょっとややこしいですが、やりたいことは先ほど言ったように足し算と掛け算を使い分けることです。
いままで引数にn1とn2を設定していたことで、好きな値を選択して計算をすることができました。同じようにして引数に関数を設定することで、足し算と掛け算を選択できるようにします。
まず足し算と掛け算の関数を作ります。
func add(no1: Int, no2: Int) -> Int {
return no1 + no2
}
func multiply(no1: Int, no2: Int) -> Int {
return no1 * no2
}
そして関数の引数に関数を設定するために、この2つの関数を要約します。
add, multiply関数は共に中身は違うけれども
「2つの整数型の入力値」から、「1つの整数型の結果」を返していると要約できます。
すなわち以下のように書くことができます。
(Int, Int) -> Int
これが関数を要約した物です。これをcalculator関数の引数の設定に使います。
実際には以下のように書きます。
func calculator(n1: Int, n2: Int, operation: (Int, Int) -> Int) -> Int {//引数に関数を設定!!
return operation(n1, n2)//引数に設定された関数を使って値を返す
}
func add(no1: Int, no2: Int) -> Int {
return no1 + no2
}
func multiply(no1: Int, no2: Int) -> Int {
return no1 * no2
}
設定する関数の名前をoperationとしました。
今までのn1,n2と同じように、名前とデータ型という引数の設定方法は感覚的には似ていますよね。
そしてそれぞれ選択された関数を使って、計算結果を返します。
func calculator(n1: Int, n2: Int, operation: (Int, Int) -> Int) -> Int {
return operation(n1, n2) //引数operationに代入された関数を使って値を返す
}
func add(no1: Int, no2: Int) -> Int {
return no1 + no2
}
func multiply(no1: Int, no2: Int) -> Int {
return no1 * no2
}
//足し算(add)を選択
calculator(n1: 2, n2: 3, operation: add) //=> 5
//掛け算(multiply)を選択
calculator(n1: 2, n2: 3, operation: multiply) //=> 6
1つ目の例では、add関数を使って足し算を
2つ目の例では、multiply関数を使って掛け算をしています。
これで引数に関数を設定することができ、calculator関数は足し算と掛け算を選択して計算結果を返す計算機になることができました。
##コードをすっきりさせる
ここでやっとクロージャの出番です。今回のクロージャの役割は、事前に定義していたadd関数とmultiply関数の記述を省略することです。
基本的なクロージャの書き方は、以下のようです。
{ (引数) -> 返り値の型 in
処理コード
}
これを参考にして先ほどのmultiply関数を、クロージャーを使って書き直してみましょう。
{ (no1: Int, no2: Int) -> Int in
return no1 * no2
}
そして、このクロージャで書かれた物を計算機を使う際の入力値の部分にそのままぶちこみます。
func calculator(n1: Int, n2: Int, operation: (Int, Int) -> Int) -> Int {
return operation(n1, n2)
}
calculator(n1: 2, n2: 3, operation: { (no1: Int, no2: Int) -> Int in
return no1 * no2
})
//=> 6
ここで何が起こったかというと、今まで事前に定義していたmultiply関数の記述を全てカットして、計算機の入力の部分に掛け算の処理をそのまま書いています。これにより関数の定義に使っていた分のコードを省くことができました。
##さらにコードを短くする
Swiftは値によって、それらの型を予測することができます。
例えば以下のようにaという変数を定義すると、Swiftでは自動的にaの型は整数型だと判断してくれます。
let a = 2
//let a: Int = 2 このようにやらなくてもいい
そして同様にして、関数の返り値の型も予測できます。
そのため私たちが型を定義していた部分のコードを以下のように省くことができます。
func calculator(n1: Int, n2: Int, operation: (Int, Int) -> Int) -> Int {
return operation(n1, n2)
}
calculator(n1: 2, n2: 3, operation: { (no1, no2) in //変数と返り値の型の設定を省いた!
return no1 * no2
})
//=> 6
さらにreturnの記述も省略できます。
そして一列にまとめると
func calculator(n1: Int, n2: Int, operation: (Int, Int) -> Int) -> Int {
return operation(n1, n2)
}
calculator(n1: 2, n2: 3, operation: { (no1, no2) in no1 * no2 }) //=> 6
このようにだいぶすっきりさせることができました。
func calculator(n1: Int, n2: Int, operation: (Int, Int) -> Int) -> Int {
return operation(n1, n2)
}
func multiply(no1: Int, no2: Int) -> Int {
return no1 * no2
}
calculator(n1: 2, n2: 3, operation: multiply) //=> 6
最初のコードと見比べてみると、使い方さえわかればクロージャを使う意義が見えてくると思います。
##まとめ
クロージャはコードをすっきりさせるためには強力な手段ですが、逆に見にくくなったりコードが増えたりすることもあります。そのためクロージャをいつ使うかの判断も重要になります。
今の所自分でクロージャを利用する場面は少ないかと思いますが、機会があったら自分も積極的に使って行こうと思いました。修正等ありましたら、指摘お願いします。