[英]Inconsistent behaviour with instance_eval
当将一个块传递给instance_eval时,它应在该实例的上下文中执行。 在该块中显式或隐式引用self时,应引用已调用instance_eval的实例。 这似乎在所有情况下都可以正常工作,除非传递已转换为proc的方法对象。 在这种情况下, self指的是定义方法的实例,而不是评估该块的实例。 这是一个代码示例,用以说明我的意思:
class A
def test(&b)
instance_eval(&b)
end
end
class B
def test_a(a)
a.test { puts self }
end
def test_b_helper(*args)
puts self
end
def test_b(a)
m = method(:test_b_helper).to_proc
a.test(&m)
end
end
a = A.new
b = B.new
b.test_a(a) #<A:0x007ff66b086c68>
b.test_b(a) #<B:0x007fa3e1886bc0>
两种测试的预期行为是返回相同的输出。 在这种情况下, 自我应引用A的实例,而不是B。
我查看了文档并进行了一些搜索,但是我无法找到有关此特殊性的信息。 我希望有一些经验丰富的Rubyists可以帮助消除这种行为上的差异。
为了澄清起见,我使用的是Ruby 1.9.2。
区别在于,Blocks和Procs是closures ,Method对象不是。
摘自D. Flanagan,Y。Matsumoto。 《 Ruby编程语言》 ,O'Reilly 2008,第2页。 204:
Method
对象和Proc
对象之间的一个重要区别是Method对象不是闭包。 Ruby的方法旨在完全独立,并且永远无法访问超出其自身范围的局部变量。 因此,Method
对象保留的唯一绑定是self
的值,self
是要在其上调用方法的对象。
现在,当将Method对象to_proc
, to_proc
self
的值绑定到B的调用实例,因此您将获得如上所述的结果。 实际上,当您创建Method
对象时, self
已经被修复。
当您考虑以下代码时,这一点特别明显:
class A
def foo
puts 'bar'
end
end
class B; end
class C < A; end
foo = A.instance_method(:foo)
# => #<UnboundMethod: A#foo>
a = A.new
foo.bind(a).call
# bar
b = B.new
foo.bind(b).call
# TypeError: bind argument must be an instance of A
c = C.new
foo.bind(c).call
# bar
简而言之: self
始终固定在Method
和UnboundMethod
对象上。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.