【问题标题】:Ruby equivalent of python nonlocalRuby 等价于 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?

【问题讨论】:

    标签: python ruby closures python-nonlocal


    【解决方案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 并不重要,它只是节省了一些输入。
      猜你喜欢
      • 2019-08-15
      • 1970-01-01
      • 2011-08-18
      • 2019-03-14
      • 2010-09-23
      • 2012-02-21
      • 2011-03-18
      • 2014-05-15
      • 1970-01-01
      相关资源
      最近更新 更多