対象: クロージャ(Swift)クロージャとは、簡単に言うと「関数」とそれが定義された「環境」がセットになったものだ。「環境」の最たるものが呼び出し元関数のローカル変数だ。つまり、クロージャは実行時にその呼び出し元関数のスコープ内にあるローカル変数にアクセスできるのだ。 また、クロージャには関数のような名前はない。Swiftでは、引数も戻り値もないクロージャを引数として受け取る関数は以下のように宣言できる。 // 引数、戻り値なしのクロージャを引数として受け取る func invokeClosure(closure: () -> ()) { // クロージャを呼び出す closure() } このinvokeClosure関数を呼び出すときには、呼び出し元ローカル変数の文字列を表示するだけのクロージャを渡す。この場合、クロージャには引数も戻り値もないので{}で囲まれたprint関数だけである。実際にクロージャが実行されるのはinvokeClosure関数に制御が移ってからだが、そのときに呼び出し元のローカル変数を参照できるのはクロージャであるが故である。 let message = "呼び出し元のローカル変数" // 呼び出したメソッド内でmessage変数にアクセスできる invokeClosure { print(message) } クロージャに引数、または戻り値がある場合、型を明示しなければならない。書き方は関数のそれと同じだが、引数の名前は書かなくて良い。 // Intの引数、戻り値Intのクロージャを引数として受け取る func invokeClosureWithParam(closure: (Int) -> (Int)) { // クロージャを呼び出し print(closure(100)) } 上記の関数を以下のように呼び出すと、クロージャが呼び出される。クロージャでは受け取った引数を2倍して返しているので、この場合は200が表示されることになる。 // クロージャの処理を呼び出し元で書ける invokeClosureWithParam { (p1: Int) -> Int in return p1 * 2 } また、上記のクロージャは省略した書き方ができ、引数は左から$0、$1、$2...で代用できる。以下のクロージャでは、受け取った引数$0を3倍して返しているので、この場合は300が表示される。 // 省略した書き方のクロージャ invokeClosureWithParam { $0 * 3 } 最後にsort関数的なものを書いてみる。sort関数は受け取った配列をソートする関数であるが、配列を昇順にソートするか降順にソートするかという挙動は、クロージャに定義する内容によって呼び出し元で決定できる。 // sort関数的な関数 func sortLike(_ array: inout [Int], isOrderedBefore: (Int, Int) -> (Bool)) { // 実際には配列のソートはしないが、こんな感じにクロージャを呼んでるはず for i in 0..<array.count - 1 { print("i: \(i) array[\(i)]: \(array[i]) array[\(i + 1)]: \(array[i + 1]) result: \(isOrderedBefore(array[i], array[i + 1]))") } } このsortLike関数では、実際には配列をソートしていないが、ソートをするとすれば隣り合う2つのIntを受け取って、それらの大小関係を判定してBoolを返すクロージャを何度も呼び出しているはずである。 // sort関数的な関数 var numbers = [1, 9, 7, 2] sortLike(&numbers) { $0 < $1 } 上記のコードの実行結果である。 i: 0 array[0]: 1 array[1]: 9 result: true i: 1 array[1]: 9 array[2]: 7 result: false i: 2 array[2]: 7 array[3]: 2 result: false (2015/02/20) () Swift 3.0対応。
Copyright© 2004-2019 モバイル開発系(K) All rights reserved.
[Home]
|