この本を見ながら進めてる↓
前回⇒「【Swift奮闘記ep24】関数オブジェクト後半(関数を引数にする、関数オブジェクトを戻り値にする)」
クロージャに入るのだが、かなり意味がわかりづらい。
コードを実際に入力したりして読み進めれば少しは理解できると思う。
クロージャとは全てのコードを自己解決できるブロックのことであり、学んだ人だけ得するようなものだ(…さっぱりわからん。)
まあとりあえずひたすらコードを打っていく。
関数のネスト
関数の中に関数を入れることを「ネストする」という。
以下のようにtenfold関数の中にmultiply関数を入れ子にする。
1 2 3 4 5 6 7 8 |
func tenfold(value: Int) -> Int { func multiply(_ a: Int,_ b: Int) -> Int { return a*b } return multiply(value, 10) } tenfold(value: 5) |
引数valueを10倍にして返す関数だ。
この状態だと、ネストした関数multiplyはtenfold関数の中だけでしか使えない状態だ。
例えば multiply(value:5)と指示してもコンパイルエラーとなる。
これは関数tenfold外ではmultiply関数は定義されていないから。
これを解決するにはネストした関数を戻り値に設定すればオッケー。
1 2 3 4 5 6 7 8 9 |
func makeMultiply() -> (Int) -> Int { func multiply(value: Int) -> Int { return value * 10 } return multiply } let math = makeMultiply() math(6) |
戻り値を(Int) -> Intに設定。これ関数の型ね。
さらにreturn multiply で戻り値の設定完了。
これで代入したり、呼び出したりできるようになるってわけ。
(←意味わからんと思っていたら、わかった。戻り値に関数を設定しておいたので、代入したり呼び出したりできるって話か。後から分かった。)
※追記
さらに付け足すと、親の関数の戻り値に子の関数を設定したので親の関数を呼び出せば子の関数が取得できるというわけだ。
でも一個疑問が生まれて、結局multiply(value:)を呼び出すんだったらそもそもそれを親の関数?にすればいいのでは?
(そもそも入れ子にする必要はあったの?ってこと)
つまりこういうこと↓
1 2 3 4 |
func multiply(a: Int) -> Int { return a * 10 } multiply(a:2) |
あ、でもこうしたら定数mathに代入したりすることができなくなるのか。なるほどなるほど。
ネストした関数による値のキャプチャ
関数の中にネストした関数では、関数のスコープ外で定義されている変数や定数をキャプチャすることができる。
(キャプチャ・・・ネストした外部にある変数や定数の値を、ネストした関数の中で常に使える状態にしておくこと。)
つまりネストした関数ではその関数内で定義していない変数や定数が使えるって事。
以下をご覧あれ。
1 2 3 4 5 6 7 8 9 |
func makeMultily(amount: Int) -> (Int) -> Int { func multiply(value: Int) -> Int { return value * amount } return multiply } let math = makeMultiply(amount: 20) math(5) |
multiply関数内では特にamountについて定義していないが普通に使えるよってのがキャプチャの効果だ。
クロージャ式
長くなりがちなコードを短く簡単に表現しよう!という考えがSwiftにはある。
クロージャ式といって関数を簡単に作成しようと、シンプルな構文が用意されている。
1 2 3 4 5 |
{(引数:型) -> 戻り値の型 in return 戻り値 } |
いちいち関数名をかいたりする手間が省ける感じ。無名関数ともいう。
実際にやってみよう。
1 2 3 4 5 |
func multiply(a: Int, b: Int) -> Int { return a * b } let math = multiply math(2, 5) |
これはa,bを引数とする単純な関数だが、クロージャ式に置き換えてみよう。
1 2 3 4 |
let closureMath = { (a: Int, b: Int) -> Int in return a * b } closureMath(2,5) |
無名関数を定数に代入して、その定数で関数を使っている。
(Int, Int ) -> Intは「2つのInt型の値を引数に取り、Int型の値を戻り値として返す」ということだ。
定数の型は型推論で(Int, Int ) -> Int型ということ。
クロージャ式は引数・戻り値の有無で構文のパターンが以下のように決まってくる。
引数なし、戻り値あり
1 2 3 4 5 |
{ 戻り値の型 in return 戻り値 } |
引数あり、戻り値なし
1 2 3 4 5 |
{ (引数: 型) in 処理 } |
引数なし、戻り値なし
1 2 3 4 5 |
{ 処理 } |
クロージャは慣れれば使い勝手が良さそうだが、たくさん使わないとなかなか慣れないな。
まだまだ続くよ。クロージャ。
続き⇒「【Swift奮闘記ep26】クロージャ後半(クロージャ式を引数や戻り値で使う、省略記法、末尾のクロージャ、クロージャとは)」
コメント