我正在尝试用 Ruby 编写一个闭包。这是用 Python 编写的代码:
def counter():
x = 0
def increment(y):
nonlocal x
x += y
print(x)
return increment
Ruby 中是否有“非本地”等价物,所以我可以从增量内部访问和更改变量 x?
我正在尝试用 Ruby 编写一个闭包。这是用 Python 编写的代码:
def counter():
x = 0
def increment(y):
nonlocal x
x += y
print(x)
return increment
Ruby 中是否有“非本地”等价物,所以我可以从增量内部访问和更改变量 x?
也许是这样的:
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
.
编辑:实例变量是不必要的,同样的事情可以通过方法局部变量来实现。这使得类是多余的,尽管在 Ruby 中很多都是在对象的上下文中发生的。
既然反对使用对象,为什么不直接使用 lambda?
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
请注意,增量器实际上返回 nil,因为您只指定输出 x 的值,而不是返回它。
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