Rubyでクロージャを書こうとしています。これは Python で書かれたコードです:
def counter():
x = 0
def increment(y):
nonlocal x
x += y
print(x)
return increment
インクリメント内から変数 x にアクセスして変更できるように、Ruby に「非ローカル」に相当するものはありますか?
Rubyでクロージャを書こうとしています。これは Python で書かれたコードです:
def counter():
x = 0
def increment(y):
nonlocal x
x += y
print(x)
return increment
インクリメント内から変数 x にアクセスして変更できるように、Ruby に「非ローカル」に相当するものはありますか?
たぶん次のようなものです:
class CGroup
def counter
@x ||= 0
lambda do |y|
@x += y
end
end
end
それで:
group = CGroup.new
c = group.counter
c.call(1)
=> 1
c.call(1)
=> 2
Python のnonlocal
.
EDIT : インスタンス変数は不要であり、メソッドのローカル変数を使用して同じことを実現できます。これにより、クラスは不要になりますが、Ruby では多くのことがオブジェクトのコンテキスト内で行われます。
オブジェクトを使用することに異論があるのに、なぜラムダを使用しないのでしょうか?
counter_generator = ->(){
x ||= 0
->(y){
x += y
puts x
}
}
i = counter_generator.call
=> #<Proc:0x00000100867508@(irb):17 (lambda)>
i.call(1)
1
=> nil
i.call(1)
2
=> nil
x の値を返すのではなく、出力するように指定しただけなので、インクリメンタは実際には nil を返すことに注意してください。
nonlocal
キーワードは、キャプチャする変数を Python に指示します。Ruby では、そのようなキーワードは必要ありません。特に明記しない限り、すべての変数がキャプチャされます。
したがって、Python コードに相当する Ruby は、ほぼそのまま変換されます。
counter = -> {
x = 0
->y {
x += y
puts x
}
}
i = counter.()
i.(2)
# 2
i.(3)
# 5
ただし、メソッド for を使用する方がおそらくより慣用的counter
です。
def counter
x = 0
->y {
x += y
puts x
}
end
i = counter
i.(2)
# 2
i.(3)
# 5