Nor*_*wap 3 ruby reflection closures self
define_method表现出以下行为:
class TestClass
def exec_block(&block) ; yield ; end
end
TestClass.new.send(:exec_block) do ; puts self ; end
# -> main
TestClass.send(:define_method, :bing) do ; puts self ; end
TestClass.new.bing
# -> <TestClass:...>
Run Code Online (Sandbox Code Playgroud)
我不明白的是传递给define_method的块应该是一个闭包.因此,它应该(至少根据我的理解)捕获在调用时所显示的selfas 的值.mainexec_block
我知道块将成为方法的主体,但我不明白行为的原因.当使用不同的方法时,为什么块会评估不同的东西?
如何使用define_method其他方法重现块的行为?即我怎么能写exec_block它输出<TestClass:...>而不是'main'?
self像任何其他变量一样被闭包捕获.我们可以通过传递Proc不同的对象实例来验证:
class A
def exec_block(&block)
block.call
end
end
class B
def exec_indirect(&block)
A.new.exec_block(&block)
end
end
block = proc { p self }
a = A.new; b = B.new
a.exec_block(&block) # => main
b.exec_indirect(&block) # => main
Run Code Online (Sandbox Code Playgroud)
但是,同样动态地BasicObject#instance_eval重新绑定self变量:
为了设置上下文,在代码执行时将变量
self设置为obj,使代码可以访问obj的实例变量
Module#define_method反过来用于instance_eval执行相关的块:
如果指定了块,则将其用作方法体.使用instance_eval [...]评估此块
注意:
A.send(:define_method, :foo, &block)
a.foo # => #<A:0x00000001717040>
a.instance_eval(&block) # => #<A:0x00000001717040>
Run Code Online (Sandbox Code Playgroud)
有了这些知识,您现在可以重写exec_block使用instance_eval:
class A
def exec_block(&block)
instance_eval(&block)
end
end
block = proc { p self }
A.new.exec_block(&block) # => #<A:0x00000001bb9828>
Run Code Online (Sandbox Code Playgroud)
如前所述,使用instance_eval似乎是运行Proc具有已修改上下文的实例的唯一方法.它可以用于在Ruby中实现动态绑定.
| 归档时间: |
|
| 查看次数: |
1166 次 |
| 最近记录: |