Ruby 等价于 python nonlocal

Posted

技术标签:

【中文标题】Ruby 等价于 python nonlocal【英文标题】:Ruby equivalent of python nonlocal 【发布时间】:2012-11-26 20:39:34 【问题描述】:

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

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

在 Ruby 中是否有一个“非本地”等效项,以便我可以从增量内部访问和更改变量 x?

【问题讨论】:

【参考方案1】:

可能是这样的:

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

【讨论】:

虽然创建了一个完全不必要的对象。 @delnan:同意。我不喜欢它。当时的想法是通过使用全局变量来避免命名空间污染。 NB 你必须避免使用全局变量来实现与问题中的函数远程相似的任何东西(返回的函数是独立的)。【参考方案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

【讨论】:

【参考方案3】:

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

【讨论】:

非常感谢!大多数在线闭包示例只使用 lambdas 来创建新函数,所以我不确定如何制作一个保持某种状态的闭包。 很高兴为您提供帮助。您可以在任何 ruby​​ 方法中使用 counter_generator 的主体,无论是方法、proc 还是 lambda,它的工作原理都是一样的。外部 lambda 并不重要,它只是节省了一些输入。

以上是关于Ruby 等价于 python nonlocal的主要内容,如果未能解决你的问题,请参考以下文章

PHP 等价于 Ruby 符号

什么是“pythonic”的 Ruby 等价物? [关闭]

python中ruby obj.send的等价物

什么是 Python itertools 的 Ruby 等价物,尤其是。组合/排列/分组?

是否有与 Ruby 符号等效的 Python?

是否有在 ruby​​ 中使用 matplotlib.image 的等价物