关闭不起作用

时间:2010-02-18 15:21:29

标签: ruby closures

如果一个块是一个闭包,为什么这个代码不起作用,以及如何使它工作?

def R(arg)
  Class.new do
    def foo
      puts arg
    end
  end
end

class A < R("Hello!")
end

A.new.foo #throws undefined local variable or method `arg' for #<A:0x2840538>

2 个答案:

答案 0 :(得分:26)

块是闭包,arg块内确实可以使用Class.new。它在foo方法中不可用,因为def启动了新范围。如果您将def替换为define_method(需要一个块),您将看到所需的结果:

def R(arg)
    Class.new do
        define_method(:foo) do
           puts arg
        end
    end
end

class A < R("Hello!")
end

A.new.foo # Prints: Hello!

答案 1 :(得分:5)

如果您动态定义类,可以根据需要更改它:

def R(arg)
  c = Class.new

  # Send the block through as a closure, not as an inline method
  # definition which interprets variables always as local to the block.
  c.send(:define_method, :foo) do
    arg
  end

  c
end

class A < R("Hello!")
end

puts A.new.foo.inspect
# => "Hello!"