6

との基本的な違いを理解していinstance_evalますclass_eval。遊んでいるときに私が発見したのは、何か奇妙なことattr_accessorです。次に例を示します。

A = Class.new
A.class_eval{ attr_accessor :x }

a = A.new
a.x = "x"
a.x
=> "x"  # ... expected

A.instance_eval{ attr_accessor :y }

A.y = "y"
=> NoMethodError: undefined method `y=' for A:Class

a.y = "y"
=> "y"      # WHATTT?

どうですか:

  1. instance_evalは、アクセサでAクラス(オブジェクト)にアクセスしませんでした
  2. それから実際にそれをAのインスタンスに追加しましたか?
4

4 に答える 4

9

最初は、あなたの理解(または直感)は正しく、メソッドは内部で定義されて#instance_evalおり#class_eval、同じではありません

A = Class.new

A.instance_eval { def defined_in_instance_eval; :instance_eval; end }
A.class_eval { def defined_in_class_eval; :class_eval; end }

A.new.defined_in_class_eval # => :class_eval
A.defined_in_instance_eval # => :instance_eval

補足:とselfはどちらも同じですが、デフォルトの定義は異なります。http://yugui.jp/articles/846を参照してくださいinstance_evalclass_eval

実際にトリックを行うのはModule#attr_accessorそれ自体です。その定義を見てください:http: //rxr.whitequark.org/mri/source/vm_method.c#620

def、コンテキスト、selfまたはデフォルトの定義を使用しません。モジュールにメソッドを「手動で」挿入するだけです。そのため、結果は直感に反します。

于 2013-01-21T02:28:57.650 に答える
2

class_evalとの違いについては、クラス メソッドの動的作成をinstance_eval参照してください。

class A; end
A.class_eval do
    attr_accessor :x
    def barx; end
    define_method :foox do; end
end

print 'A.instance_methods  : '; p A.instance_methods(false).sort
print 'A.singleton_methods : '; p A.singleton_methods

class B; end
B.instance_eval do
    attr_accessor :y
    def bary; end
    define_method :fooy do; end
end

print 'B.instance_methods  : '; p B.instance_methods(false).sort
print 'B.singleton_methods : '; p B.singleton_methods

class C; end
singleton_class = class << C; self end
singleton_class.instance_eval do
    attr_accessor :z
    def barz; puts 'where is barz ?' end
    define_method :fooz do; end
end

print 'C.instance_methods  : '; p C.instance_methods(false).sort
print 'C.singleton_methods : '; p C.singleton_methods

print 'singleton_class.barz : '; singleton_class.barz
print 'singleton_class.methods  : '; p singleton_class.methods(false)

出力 (ルビー 1.8.6):

A.instance_methods  : ["barx", "foox", "x", "x="]
A.singleton_methods : []
B.instance_methods  : ["fooy", "y", "y="]
B.singleton_methods : ["bary"]
C.instance_methods  : []
C.singleton_methods : ["z", "z=", "fooz"]
singleton_class.barz : where is barz ?
singleton_class.methods  : ["barz"]

B でわかるように、instance_eval は通常シングルトン メソッドを作成しますが、明らかにインスタンス メソッドの定義attr_accessordefine_method強制します。

于 2013-01-21T00:56:20.893 に答える
1
A.singleton_class.class_eval { attr_accessor :y }
A.y = 'y'
A.y
于 2013-01-21T06:09:11.997 に答える
0

このメソッドattr_accessorは、 class の本体で呼び出されると、そのクラスインスタンスでアクセサ メソッドが定義されるようなクラス メソッドです。

を行うと、クラスの本体A.class_eval{...}内でそれを呼び出しているため、などのインスタンスにアクセサーが割り当てられます。 Aa

を行うと、クラスの非本体A.instance_eval{...}内で呼び出すため、そのインスタンスにはアクセサーが割り当てられません。 A

そうする場合、クラスの本体Class.class_eval{attr_accessor :z}でそれを呼び出しているため、そのインスタンスにはアクセサが割り当てられます。 ClassAA.z = ...

于 2013-01-21T00:55:50.397 に答える