将块传递给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>
预期的行为是两个测试都返回相同的输出。在这种情况下, self 应该引用A的实例,而不是B.
我查看了文档并进行了一些搜索,但我无法找到有关这种特性的信息。我希望有一些经验丰富的Rubyist可以帮助消除这种行为上的差异。
只是为了澄清,我使用的是Ruby 1.9.2。
答案 0 :(得分:3)
区别在于,Blocks和Procs是闭包,而Method对象则不是。
摘录自D. Flanagan,Y。Matsumoto。 Ruby Programming Language ,O'Reilly 2008,p。 204:
Method
个对象和Proc
个对象之间的一个重要区别是 Method对象不是闭包。 Ruby的方法旨在 是完全独立的,他们永远无法访问本地 变量超出了自己的范围。唯一保留的绑定 因此,Method
对象是self
的值 - 在其上的对象 方法是被调用的。
当您现在转换Method对象to_proc
时,将self
的值绑定到B的调用实例,因此您将获得上述结果。实际上,在创建self
对象时,Method
已经修复。
当您考虑以下代码时,这一点尤为明显:
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
个对象上。