define_method 里面 instance_eval
define_method inside instance_eval
当我在 instance_eval 块中为 class 定义一个方法时,它创建了一个很好的 class 方法。
例)
class A
end
A.instance_eval do
def method; end
end
A.method #works
但是当我在 instance_eval 中使用 define_method 时,它会创建实例方法而不是 class 方法
例如)
A.instance_eval do
define_method(:method1) {}
end
A.method1 # NoMethodError: undefined method `method1'
A.new.method1 # Works fine
以上现象我无法理解。请有人帮帮我。
如果您在 实例 (这是它的主要目的)的上下文中查看 instance_eval
,这种古怪的行为会更有意义。
class A
end
a = A.new
a.instance_eval do
def foo
end
end
foo
在哪里定义的?我能想到的唯一明智的地方就是a
的单例class,确实如此
a.method(:foo).owner == a.singleton_class
# true
所以这证明了规则
def
inside instance_eval
defines a method in self
's singleton class.
这和你看到的完全一致。
A.instance_eval do
# defines method in A's singleton class!
def method; end
end
那么为什么 define_method
表现不同呢?因为与 def
不同,它是 方法 !所以这个
A.instance_eval do
define_method(:foo) {}
end
真的只是
A.define_method(:foo) {}
这是创建普通实例方法的元编程方式。这种不一致可能看起来很烦人,但再看看正常实例的情况,您就会明白为什么 def
和 define_method
不能 一致。这个
a.instance_eval do
define_method(:foo) {}
end
真的只是
a.define_method(:foo) {}
胡说八道
NoMethodError: undefined method `define_method' for #<A:0x00008>
对于:
class A; end
A.instance_eval do
puts "self=#{self}"
def m; puts "hi"; end
define_method(:n) {puts "ho" }
end
#=> "self=A"
我们发现:
A.methods(false) #=> [:m]
A.instance_methods(false) #=> [:n]
A.m # hi
A.n # NoMethodError:...
A.new.m # NoMethodError:...
A.new.n # ho
A.instance_eval
打开 class A
并且在 A
上定义了方法 m
。接下来,调用方法 define_method,它在其接收者 A
.
上创建实例方法 :n
假设我们要使用 Module#class_eval rather than BasicObject#instance_eval:
A.class_eval do
puts "self=#{self}"
def m; puts "hi"; end
define_method(:n) {puts "ho" }
end
#=> "self=A"
我们发现:
A.methods(false) #=> []
A.instance_methods(false) #=> [:m, :n]
A.m # NoMethodError:...
A.n # NoMethodError:...
A.new.m # hi
A.new.n # ho
所以你看到这个行为是一样的:
class A
puts "self=#{self}"
def m; puts "hi"; end
define_method(:n) {puts "ho" }
end
这里的实例方法可以用 def
或 define_method
.
定义
记住这个:
changes self
to
changes current class
to
class_eval
receiver
receiver
instance_eval
receiver
receiver's singleton class
在 ruby 中使用 def
关键字(没有明确的接收者)定义的方法总是在“当前 class” 中定义(这就是 Paolo Perrotta 在 元编程Ruby;别人叫它“default definee”)
“current class”是我们通常不会考虑的东西,因为它很直观;在 class 定义中,当前 class 是 class 本身,因此在 class 定义中用 def foo
定义的方法成为 [=49] 的实例方法=].
但是当你调用 instance_eval 并且 A
class 作为接收者时,根据上面的 table,你正在将 'current class' 更改为接收者的单例class;由于您正在使用 def
定义方法,因此它将在 'current class' 中定义,这将导致 'class method'(在 A 的单例 class 或 eigen[= 中定义的方法49=]):
class A
end
A.instance_eval do
# the current class here is not A, but A's singleton class;
def method; end
end
但是,当您使用 define_method
定义方法时,按照上面的 table,您实际上是在隐式接收器 self
上调用 define_method
;如果你查看 table,self
将是接收者 A
,因此它与调用 A.define_method
甚至:
相同
class A
define_method(:method1) {}
end
所以这就是为什么,在这种情况下,你得到一个实例方法,因为你在 class A 上调用了 define_method,而不是在 A 的单例 class 中调用(或者也称为本征class).
当我在 instance_eval 块中为 class 定义一个方法时,它创建了一个很好的 class 方法。
例)
class A
end
A.instance_eval do
def method; end
end
A.method #works
但是当我在 instance_eval 中使用 define_method 时,它会创建实例方法而不是 class 方法 例如)
A.instance_eval do
define_method(:method1) {}
end
A.method1 # NoMethodError: undefined method `method1'
A.new.method1 # Works fine
以上现象我无法理解。请有人帮帮我。
如果您在 实例 (这是它的主要目的)的上下文中查看 instance_eval
,这种古怪的行为会更有意义。
class A
end
a = A.new
a.instance_eval do
def foo
end
end
foo
在哪里定义的?我能想到的唯一明智的地方就是a
的单例class,确实如此
a.method(:foo).owner == a.singleton_class
# true
所以这证明了规则
def
insideinstance_eval
defines a method inself
's singleton class.
这和你看到的完全一致。
A.instance_eval do
# defines method in A's singleton class!
def method; end
end
那么为什么 define_method
表现不同呢?因为与 def
不同,它是 方法 !所以这个
A.instance_eval do
define_method(:foo) {}
end
真的只是
A.define_method(:foo) {}
这是创建普通实例方法的元编程方式。这种不一致可能看起来很烦人,但再看看正常实例的情况,您就会明白为什么 def
和 define_method
不能 一致。这个
a.instance_eval do
define_method(:foo) {}
end
真的只是
a.define_method(:foo) {}
胡说八道
NoMethodError: undefined method `define_method' for #<A:0x00008>
对于:
class A; end
A.instance_eval do
puts "self=#{self}"
def m; puts "hi"; end
define_method(:n) {puts "ho" }
end
#=> "self=A"
我们发现:
A.methods(false) #=> [:m]
A.instance_methods(false) #=> [:n]
A.m # hi
A.n # NoMethodError:...
A.new.m # NoMethodError:...
A.new.n # ho
A.instance_eval
打开 class A
并且在 A
上定义了方法 m
。接下来,调用方法 define_method,它在其接收者 A
.
:n
假设我们要使用 Module#class_eval rather than BasicObject#instance_eval:
A.class_eval do
puts "self=#{self}"
def m; puts "hi"; end
define_method(:n) {puts "ho" }
end
#=> "self=A"
我们发现:
A.methods(false) #=> []
A.instance_methods(false) #=> [:m, :n]
A.m # NoMethodError:...
A.n # NoMethodError:...
A.new.m # hi
A.new.n # ho
所以你看到这个行为是一样的:
class A
puts "self=#{self}"
def m; puts "hi"; end
define_method(:n) {puts "ho" }
end
这里的实例方法可以用 def
或 define_method
.
记住这个:
changes self to |
changes current class to |
|
---|---|---|
class_eval | receiver | receiver |
instance_eval | receiver | receiver's singleton class |
在 ruby 中使用 def
关键字(没有明确的接收者)定义的方法总是在“当前 class” 中定义(这就是 Paolo Perrotta 在 元编程Ruby;别人叫它“default definee”)
“current class”是我们通常不会考虑的东西,因为它很直观;在 class 定义中,当前 class 是 class 本身,因此在 class 定义中用 def foo
定义的方法成为 [=49] 的实例方法=].
但是当你调用 instance_eval 并且 A
class 作为接收者时,根据上面的 table,你正在将 'current class' 更改为接收者的单例class;由于您正在使用 def
定义方法,因此它将在 'current class' 中定义,这将导致 'class method'(在 A 的单例 class 或 eigen[= 中定义的方法49=]):
class A
end
A.instance_eval do
# the current class here is not A, but A's singleton class;
def method; end
end
但是,当您使用 define_method
定义方法时,按照上面的 table,您实际上是在隐式接收器 self
上调用 define_method
;如果你查看 table,self
将是接收者 A
,因此它与调用 A.define_method
甚至:
class A
define_method(:method1) {}
end
所以这就是为什么,在这种情况下,你得到一个实例方法,因为你在 class A 上调用了 define_method,而不是在 A 的单例 class 中调用(或者也称为本征class).