3

私は Pickaxe 1.9 を使って作業を進めていますが、instance/class_eval ブロッ​​クの定数ルックアップに少し混乱しています。私は1.9.2を使用しています。

Ruby は *_eval ブロッ​​ク内の定数ルックアップをメソッド ルックアップと同じ方法で処理しているようです。

  1. receiver.singleton_class (および mixins) で定義を探します。
  2. 次に、receiver.singleton_class.superclass (および mixins) で。
  3. 次に、 に到達するまで固有連鎖を続けます#<Class:BasicObject>
  4. そのスーパークラスは Class です。
  5. そして、残りの先祖チェーン (Objectトップレベルで定義したすべての定数を格納する を含む) を上に移動し、途中で mixin をチェックします。

これは正しいです?つるはしの議論は少し簡潔です。

いくつかの例:

class Foo
  CONST = 'Foo::CONST'
  class << self
    CONST = 'EigenFoo::CONST'
  end
end

Foo.instance_eval { CONST } # => 'EigenFoo::CONST'
Foo.class_eval { CONST } # => 'EigenFoo::CONST', not 'Foo::CONST'!
Foo.new.instance_eval { CONST } # => 'Foo::CONST'

class_eval の例では、Foo-the-class は Foo-the-object の祖先チェーンに沿ったストップではありません!

ミックスインの例:

module M
  CONST = "M::CONST"
end
module N
  CONST = "N::CONST"
end

class A
  include M
  extend N
end

A.instance_eval { CONST } # => "N::CONST", because N is mixed into A's eigenclass
A.class_eval { CONST } # => "N::CONST", ditto
A.new.instance_eval { CONST } # => "M::CONST", because A.new.class, A, mixes in M
4

2 に答える 2

1

1.9.2では、定数ルックアップが再び変更され、1.8.7の動作と同等になりました。

class A
  class B
    class C
    end
  end
end

A.class_eval { B } # => NameError
A.instance_eval { B } # => NameError
A.new.instance_eval { B } # => A::B

基本的に、定数は準字句スコープです。これは1.9.xブランチと1.8.xブランチの間で異なるために使用され、ライブラリの相互互換性が面倒だったため、元に戻しました。

イェフダ・カッツの(成功した)1.8の行動を回復するためのアピール

于 2010-12-15T21:28:36.510 に答える
0

定数は実質的にレキシカル スコープであるため、それらが定義されているモジュール階層の外側で簡単にアクセスすることはできません。hereには適切な説明があり、少しトピックから外れていますが、こちらをよく読んでください

于 2016-01-26T04:18:33.550 に答える