6

当我编写采用可选块的方法时,我通常使用类似

block.call if block_given?

但是,在像下面这样动态定义的方法中,block_given?似乎不起作用。

class Foo
  %w[bar baz].each do |method_name|
    define_singleton_method(method_name) do |&block|
      puts "Was #{method_name} given a block? #{block_given?}"
      puts block.call
    end
  end
end

Foo.bar { puts 'I am a block' }

该块按预期调用,但block_given?返回 false。

为什么是这样?

4

1 回答 1

9

块是闭包,因此它们会记住局部变量(例如method_name)。他们还记得块:yield并且block_given?正在寻找在define_method被调用时处于活动状态的块,而不是传递给的块bar。没有,所以给定的块返回 false。

一个更好的例子是

def create_method
  define_singleton_method('foo') do |&block|
    puts "Was given a block? #{block_given?}"
    puts yield
    puts block.call
  end
end

create_method {'block passed to create_method'}
foo {'block passed to the created method'}

哪个输出

Was given a block? true
block passed to create_method
block passed to the created method
于 2012-08-22T10:08:09.997 回答