Ruby でクロージャ

クロージャってブロックとしてよく使っているが、何者なのかよくわかってなかった。
急に気になったので調べてみた。ただし Wikipedia
クロージャ - Wikipedia

典型的には、クロージャはある関数全体が他の関数(以下、エンクロージャ)の内部で宣言されたときに発生し、内部の関数はエンクロージャのローカル変数(レキシカル変数)を参照する。実行時に外部の関数が実行された際、クロージャが形成される。クロージャは内部の関数のコードとエンクロージャのスコープ内の必要なすべての変数への参照からなる。

内部で宣言された関数は、宣言を行った関数内のローカル変数を参照できるってことかね。

サンプルコード

Wikipedia に 載ってた Javascript のカウンタを Ruby で書いてみた。

#!/usr/bin/env ruby
def count
  i = 0
  lambda {i += 1}
end

c1 = count
5.times do |i|
  puts c1.call
end
# >> 1
# >> 2
# >> 3
# >> 4
# >> 5


ちなみに関数の引数を利用することもできる。

#!/usr/bin/env ruby
def count i
  lambda {i += 1}
end

c1 = count 0
5.times do |i|
  puts c1.call
end

サンプルその2

これは間違いっぽい。
呼び出した関数のローカル変数ではなく、クラス内に値を保持してしまっているから。
やってることは似てるけど。

#!/usr/bin/env ruby
class Hoge
  def initialize
    @x = 0
  end
  def count
    return lambda{ @x += 1 }
  end
end

h = Hoge.new
5.times do |i|
  puts h.count.call
end