クロージャは、定義されているコンテキストにある定数や変数をキャプチャすることができます。クロージャは、定数や変数が定義されていた元のスコープにもはや存在しなくなっている場合でも、それらの定数や変数の値をクロージャの本体内から参照あるいは変更することができます。
Swift では、値をキャプチャできるクロージャの最もシンプルな形式は、別の関数の本体内に記述されるネストされた関数です。ネストされた関数は、外側の関数の引数をキャプチャすることができ、外側の関数内に定義されている定数や変数をキャプチャすることも可能です。
次はネストされた関数 incrementer
を含む、関数 makeIncrementer
の例です。ネストされた関数 incrementer()
は、runningTotal
と amount
の値をコンテキストからキャプチャします。これらの値をキャプチャした後、呼び出されるたびに runningTotal
を amount
増加させるクロージャとして、incrementer
が makeIncrementer
から返されます。
func makeIncrementer(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
return incrementer
}
makeIncrementer
の戻り値の型は () -> Int
です。つまり、シンプルな値ではなく、関数を返します。返されるこの関数にはパラメータが無く、呼び出されるたびに Int
値を返します。関数が別の関数を返せることについては、Function Types as Return Types を確認してください。
関数 makeIncrementer(forIncrement:)
は、incrementer
が返す現在の累計数を保持する整数の変数 runningTotal
を定義しています。この変数は 0
で初期化されています。
関数 makeIncrementer(forIncrement:)
には外部名が forIncrement
で、ローカル名が amount
の Int
パラメータが 1 つあります。このパラメータに渡される引数の値には、返される関数の incrementer
が呼び出されるたびに runningTotal
を増加させる数を指定します。関数 makeIncrementer
は、実際の増加処理を実行するネストされた関数 incrementer
を定義しています。この関数は、単に runningTotal
に amount
を追加し、結果を返します。
切り離して考えると、ネストされた関数 incrementer()
は通常とは異なります。
func incrementer() -> Int {
runningTotal += amount
return runningTotal
}
関数 incrementer()
にはパラメータが無いにもかかわらず、その関数の本体から runningTotal
と amount
を参照しています。関数の周辺から runningTotal
と amount
の参照をキャプチャし、その関数の本体内で使用します。参照をキャプチャすることで、makeIncrementer
の呼び出しが終了したときに runningTotal
と amount
が消失せず、次に関数 incrementer
が呼び出されるときに runningTotal
を利用できるようにもしています。
最適化として、値がクロージャによって変更されない、かつクロージャが生成された後に値が変更されない場合には、Swift は値のコピーを代わりにキャプチャして保持することがあります。
また Swift は、変数が必要なくなったときの変数の破棄に関わるすべてのメモリ管理についても処理します。
次は makeIncrementer
の実行例です。
let incrementByTen = makeIncrementer(forIncrement: 10)
この例では、呼び出されるたびに変数 runningTotal
に 10
を加える関数 incrementer
を、定数 incrementByTen
が参照するよう設定しています。
incrementByTen()
// 値 10 を返す
incrementByTen()
// 値 20 を返す
incrementByTen()
// 値 30 を返す
もう一つの incrementer
を生成した場合、別の新しい変数 runningTotal
の参照を独立して保持します。
let incrementBySeven = makeIncrementer(forIncrement: 7)
incrementBySeven()
// 値 7 を返す
元の incrementer
(incrementByTen
) を再び呼び出すと、独自の変数 runningTotal
を加算しますが、incrementBySeven
でキャプチャされた変数には影響しません。
incrementByTen()
// 値 40 を返す
Portions of this page are translations based on work created and shared by Apple and used according to terms described in the Creative Commons Attribution 4.0 International License.