7

我正在尝试用 Ruby 编写一个闭包。这是用 Python 编写的代码:

def counter():
    x = 0
    def increment(y):
        nonlocal x
        x += y
        print(x)
    return increment

Ruby 中是否有“非本地”等价物,所以我可以从增量内部访问和更改变量 x?

4

3 回答 3

2

也许是这样的:

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 中很多都是在对象的上下文中发生的。

于 2012-12-09T01:58:38.210 回答
2

既然反对使用对象,为什么不直接使用 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 的值,而不是返回它。

于 2012-12-09T02:15:26.987 回答
2

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
于 2012-12-09T02:39:08.080 回答