はじめに
クロージャについての理解がまだまだ浅く、なんとなくの理解となっているため、
私の頭の中を整理する意味でまとめていきます。
クロージャについて
そもそもクロージャとはなにか? についてSwift実践入門より以下を引用させていただきます。
クロージャは、再利用可能なひとまとまりの処理です。
クロージャにはクロージャ式という定義方法があります。
クロージャ式は名前が不要であったり、型推論によって型の記述が省略可能であったりと、関数よりも手軽に定義できます。
基本構文
クロージャは{ }を使用して、以下のフォーマットで記述します。
{ (引数名1:型,引数名2:型....) -> 戻り値の型 in
//実行時の処理
return 返却値
}
上記に従い実際に記述すると以下のようになります。
let equal = { (val1:Int,val2:Int) -> Bool in
//実行時の処理
return val1 == val2
}
(val1:Int,val2:Int)でInt型の値を2つ受け取り、Bool型の値を返します。
上記で実際に返却される値はval1とval2を比較したBool型の結果です。
これを変数equalに代入しています。
クロージャの呼び出し
クロージャを呼び出す際は、クロージャが代入されている変数名の後ろに( )をつけて、( )の中に受け渡す値を記述します。
let equal = { (val1:Int,val2:Int) -> Bool in
//実行時の処理
return val1 == val2
}
//呼び出し
equal(10,20)//false
equal(20,20)//true
糖衣構文(シンタックスシュガー)
クロージャを呼び出す際の値や変数宣言によって、型を自動的に推論できる場合は 、クロージャの引数の型を省略出来ます。
また、処理が単文の場合はreturnも省略可能です。
//変数宣言
let equal :(Int,Int) -> Bool
//クロージャを代入
equal = { (val1,val2) in
//実行時の処理
val1 == val2
}
//呼び出し
equal(10,20)//false
equal(20,20)//true
引数が無く、戻り値も無いクロージャは以下のように ( ) -> Void in と記述出来ます。
let closure = { () -> Void in
print("Hello")
}
//呼び出し
closure()//Hello
さらに、( ) -> Void in も省略出来ます。
let closure = {
print("Hello")
}
//呼び出し
closure()//Hello
クロージャのスコープ
//変数宣言
var closure :() -> Void
do{
var count = 0
closure = {
count = count + 1
print(count)
}
}
//呼び出し
closure()//1
closure()//2
//print(count) //doのスコープ外からはcountにアクセスできないためコンパイルエラー
クロージャのスコープについて見ていきましょう。
do文の{}の中で宣言された変数countは、do文の{}の中のみが影響範囲となっており、本来、do文の外からのアクセスは出来ません。
しかし、クロージャは自身が定義されたスコープの変数への参照を保持しているため、do文の外からクロージャを通してcountの値を変更することが出来ます。この機能をキャプチャといいます。
トレイリングクロージャ
トレイリングクロージャとは関数の引数の最後にクロージャを渡した場合にクロージャを( )の外側に記述することができる方法です。
これにより、可読性が向上します。
func greeting(name:String,handler:(String) -> Void){
handler(name)
}
//トレイリングクロージャあり
greeting(name: "ポチ") { val in
print("\(val)さんこんにちは")
}
//トレイリングクロージャなし
greeting(name:"ポチ",handler:{ val in
print("\(val)さんこんにちは")
})
//実行結果
//ポチさんこんにちは
//ポチさんこんにちは