この本を見ながら進めてる↓
前回⇒「【Swift奮闘記ep25】クロージャ前半(関数のネスト、ネストした関数による値のキャプチャ、クロージャ式)」
なんとなく流しながらこなしてきたクロージャだが、後半戦はさらに流しながら進んでいこうと思う。クロージャむずいっ><
クロージャ式を引数や戻り値で使う
クロージャ式によって作成した関数オブジェクトは、引数や戻り値にすることができる。
「引数:2つの整数と1つの関数」を引数にもつ関数をみてみる。
1 2 3 4 5 6 7 |
func operate(a: Int, b: Int, function: (Int, Int) -> Int) -> Int { return function(a, b) } operate(a: 1, b: 2, function: { (a: Int, b: Int) -> Int in return a + b }) |
aとbを足す関数を引数としてセットしたから、関数operateを実行するとaとbが足される。
次にネストされた関数。値のキャプチャが行われている。⇒つまりネストされた関数はamountが定義されていないけどmakeMultiplyで定義されているからamount使えるよってこと。
1 2 3 4 5 6 7 |
func makeMultiply(amount: Int) -> (Int) -> Int { return { (value: Int) -> Int in return value * amount } } let multiply = makeMultiply(amount: 20) multiply(5) |
クロージャ式を使う以前にネストされた関数の意味もわからなくちゃいけないし、単純な関数の仕組み(引数とか)は押さえておかなきゃいけない。
クロージャ式の省略記法
クロージャ式を使うことでコードが簡略化してスッキリするのだが、全ての関数に対してクロージャ式が使えるわけではない。
「クロージャ式で指定しなくても、関数の型が明確にわかる場合のみ」省略することができる。ということで、ちょっと見ていこう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//1つ目 var closure: (Int, Int) -> Int = { (a: Int, b: Int) -> Int in return a * b } closure(2, 3) //2つ目 closure = { a, b in return a * b } closure(2, 3) //3つ目 closure = { a, b in a * b } closure(2, 3) //4つ目 closure = { $0 * $1 } closure(2, 3) |
これらは全て同じ意味になる。
returnが省略できる場合は「in以降のコードが1行だけの場合(returnから始まるコードだけの場合)」である。それ以外の場合がわからないが、とりあえずreturnも省略できる場合があるとだけ覚えておこう。
$0 * $1 ってのは省略の最終形態みたいな感じで、0番目と1番目の引数を掛け合わせますよっていう意味。
あまりにシンプルすぎて後からコードを見て「なんだこれ?」にならないように注意しよう。
末尾のクロージャ
関数の引数の最後がクロージャとなる場合、省略系を使うことができる。
以下のコードは、引数はclosure関数1つなので末尾の関数とも言える。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
func take(closure: () -> Void) { closure() } //1つ目の呼び出し方 take(closure: { print("Hello!") }) //2つ目の呼び出し方 take() { print("Hi!") } //3つ目の呼び出し方 //引数が関数1つの場合に限り()を省略 take { print("What's up?") } |
print(“Hello!”)もprint(“Hi!”)もprint(“What’s up?”)も引数なしの戻り値なしなのでclosureの関数の型は「( ) -> Void」 。
それぞれ3通りの呼び出し方がある。
3つ目については引数が関数1つの時に限るので使う場面は少ないかもしれない。
クロージャとは
改めてクロージャについて説明すると、クロージャとは「すべてのコードを自己解決できるブロック」のことを言う。
ブロックとは{ }で囲まれた中のもののこと(ここでは関数のこと)で、自己解決っていうのはブロックだけ単独で見ても「いつでも呼び出し可能な状態である。」ということである。
クロージャと呼ぶことができるブロックには以下の3つがある。
- ネスとされた関数は、値をキャプチャすることができるクロージャである。
- グローバルな関数(ネストされていない関数)は、値をキャプチャすることができないクロージャである。
- クロージャ式は、周囲から値をキャプチャすることができる無名なクロージャである(無名関数)。
1つ目に関して言えば、(以前も紹介したが)関数がネストされていれば中の関数で定義しなくても使えるよってことだ。amountのとこで出てきた話だね。
2つ目に関して言えば、値はキャプチャ(amountのとこで話したテクニック的なこと)はできないが、グローバルな変数を活用して、グローバルな関数は自己解決しているからクロージャだよって話。つまり関数の外で変数が定義されているので関数の中でも普通に使えますよねっ、だから関数内では全く矛盾ありませんよね?(自己解決ですよね?)って話。
3つ目に関して言えば、クロージャ式も1つ目のネストされた関数と同様に、値をキャプチャできるので、自己解決している(つまり)クロージャだよねって話。
クロージャの終わりに
もはや不毛な戦いみたいになっているような感じだが、このクロージャの話は比較的わかったかもしれない。
ま、とりあえず先へ進んでみようと思う。
※追記
クロージャ式を使わなくても普通にアプリは作れるので、とりあえず現段階では習得しなくていいと思う。
正直何回本の解説を読んでもクロージャ式とか一体なんなのかがわからないわ。
といってもSwiftの発展的な文法はラストのキャストの型を残すのみとなった。(やっとだよ〜ふぅ〜)
気を引き締めて行きたい。
コメント