隐式块传递和动态定义的方法

时间:2014-10-12 15:24:22

标签: ruby metaprogramming proc

请考虑以下不同方法来定义方法m

  • 方法1:

    class C
      def m; yield; end
    end
    
  • 方法2:

    class C
      def initialize
        (class << self; self; end).class_eval do            
          define_method(:m){|&b| b.call }
        end
      end
    end
    
  • 方法3:

    class C
      def initialize
        (class << self; self; end).class_eval do            
          define_method(:m){puts block_given?; yield}            
        end
      end
    end
    

然后我可以使用m调用Object#send

o = C.new
o.send(:m) {puts 'test'}

使用方法1或方法2调用m时工作正常,方法3会出现此错误:

no block given (yield) (LocalJumpError)

我理解一个块不是一个对象,而只是方法调用语法的一部分,你不能将一个隐式块从一个函数传递给另一个函数而不用像这样模糊的东西:

def printer
  yield
end
def proxy
  printer &Proc.new
end

proxy { puts "&Proc.new probably creates Proc object from block"}

但在那种情况下,为什么方法1有效?获得一个可以解释幕后发生的事情的答案真是太棒了。

1 个答案:

答案 0 :(得分:3)

方法3的问题在于范围。 yield是指传递给initialize的块,如果有的话。它没有引用传递给m的块。由于您在o之前创建了C.new而没有阻止,因此缺少预期的yield,这会导致错误。

在方法1中,yield指的是传递给m的块。在方法2中,b指的是从传递给m的块转换的proc。