0

ブロックを 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は B ではなく A のインスタンスを参照する必要があります。

ドキュメントを調べていくつか検索しましたが、この特異性に関する情報を見つけることができませんでした。この動作の違いを解決するのに役立つ経験豊富な Rubyist が何人かいることを願っています。

明確にするために、私はRuby 1.9.2を使用しています。

4

1 に答える 1

3

違いは、Blocks と Proc はクロージャであり、Method オブジェクトはそうではないということです。

D. フラナガン、Y. 松本からの抜粋。Ruby プログラミング言語、O'Reilly 2008、p. 204:

Methodオブジェクトとオブジェクトの重要な違いの 1 つProcは、メソッド オブジェクトがクロージャではないことです。Ruby のメソッドは完全に自己完結型であることを意図しており、独自のスコープ外のローカル変数にアクセスすることはありません。したがって、オブジェクトによって保持される唯一のバインディングは 、メソッドが呼び出されるオブジェクトMethodの値です。self

Method objectto_procをキャストすると、 の値が B の呼び出しインスタンスにバインドselfされるため、上記の結果が得られます。実際に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ます。

于 2012-07-09T17:01:23.777 に答える