当我在instance_eval块中为类定义一个方法时,它会创建一个很好的类方法。
例如)
class A
end
A.instance_eval do
def method; end
end
A.method #works
但是当我在instance_eval中使用define_method时,它会创建实例方法而不是类方法例如)
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
的singleton类,事实上这就是真正的
a.method(:foo).owner == a.singleton_class
# true
因此,这证明了规则
instance_eval
中的def
在self
的singleton类中定义了一个方法。
这与你所看到的完全一致。
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>
记住这个:
将self 更改为 |
将current class 更改为 |
|
---|---|---|
类_值 | 接收器 | 接收器 |
instance_eval | 接收器 | 接收者的单例类 |
用于:
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
打开类A
,方法m
在A
上定义。接下来,调用方法define_method,它在其接收器A
上创建实例方法:n
。
假设我们使用模块#class_eval而不是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
并且这里实例方法可以用CCD_ 19或CCD_。