Ruby相当于python nonlocal

时间:2012-12-09 01:49:09

标签: python ruby closures python-nonlocal

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

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

Ruby中是否存在“非本地”等效项,因此我可以从内部增量中访问并更改变量x?

3 个答案:

答案 0 :(得分: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中的很多内容都发生在对象的上下文中。

答案 1 :(得分: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

请注意,incrementor实际上返回nil,因为你只指定输出x的值,而不是返回它。

答案 2 :(得分:2)

nonlocal关键字告诉Python要捕获哪些变量。在Ruby中,您不需要这样的关键字:除非另有明确说明,否则将捕获所有变量。

因此,与Python代码相当的Ruby几乎可以直接翻译:

counter = -> {
  x = 0
  ->y {
    x += y
    puts x
  }
}

i = counter.()

i.(2)
# 2

i.(3)
# 5

使用counter的方法可能更为惯用,但是:

def counter
  x = 0
  ->y {
    x += y
    puts x
  }
end

i = counter

i.(2)
# 2

i.(3)
# 5