簡體   English   中英

與instance_eval的行為不一致

[英]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_procto_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始終固定在MethodUnboundMethod對象上。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM