クロージャー
読み:クロージャー
外語:closure
サブルーチンへのリファレンス(ポインター)と、そのプライベートなデータをセットにしたもの。日本語では閉包と呼ぶらしい。
概要
簡単には、ラムダ式や無名関数などの関数オブジェクトのことである。
プログラミング言語が高階関数に対応していてラムダ式などの関数を返すことができ、なおかつプログラミング言語が第一級関数に対応していて関数オブジェクトを変数に代入して関数リテラルとして使うことができる場合、そういった関数リテラルをクロージャーとして使うことができる。
LispやPerl、JavaScript、Groovy、Kotlinなどで使われる。
特徴
機能
通常の関数であれば、関数内で定義された変数は関数終了時点で破棄される。
しかし関数オブジェクトを変数に代入するとなると事情が変わってくる。この時はその代入された変数が有効である間は保持されるため、その間はクロージャーを複数回呼び出した時には前回の値が継続して使用される。
Kotlinでの例
上述の説明をKotlinを使って説明する。例えば、次のようなクロージャーを定義する。
fun increment(): ()->Int {
var num = 0
return {
++num
}
}
この関数自体は引数を持たないが、内部にもつ変数をインクリメントしながら返すラムダ式を返す。
これを実際に使ってみる。
fun main() {
val closure = increment()
println(closure())
println(closure())
println(closure())
}
これは次のような結果を返す。
1
2
3
メリット
同じことをクロージャーを使わないで書くことも一応はできる。
fun main() {
var num = 0
val increment = { ++num }
println(closure())
println(closure())
println(closure())
}
この場合、numは関数内のどこからでもアクセスできてしまう。ここで「変数の名前衝突」という問題が発生しうることと、意図しない変更が生じうるという問題がある。特定目的の変数はできるだけカプセル化(隠蔽化)されるのが望ましい。
そこで必要な処理をクロージャーというまとまりで定義することで、こういった問題を解決することができる。
再検索