当我在class中为instance_eval块定义一个方法时,它会创建一个很好的类方法。
Eg)的
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
我无法理解上述现象。请有人帮助我。
答案 0 :(得分:2)
如果你在实例(这是它的主要目的)的上下文中查看instance_eval
,这种古怪的行为会更有意义。
class A
end
a = A.new
a.instance_eval do
def foo
end
end
foo
在哪里定义?我能想到的唯一合理的地方是a
的单身人士,确实是真的
a.method(:foo).owner == a.singleton_class
# true
所以这证明了规则
def
内的{p>instance_eval
定义了self
的单例类中的方法。
这与你所看到的完全一致。
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>
答案 1 :(得分:0)
有关:
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,在其接收方:n
上创建实例方法A
。
假设我们使用Module#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
此处可以使用def
或define_method
来定义实例方法。
答案 2 :(得分:0)
记住这一点:
将 self 更改为 |
将 current class 更改为 |
|
---|---|---|
class_eval | 接收器 | 接收器 |
instance_eval | 接收器 | 接收者的单例类 |
在 ruby 中使用 def
关键字(没有显式接收器)定义的方法总是在“当前类”中定义(这就是 Paolo Perrotta 在 Metaprogramming Ruby 中所称的;其他人称之为"default definee")
“当前类”是我们通常不会考虑的东西,因为它很直观;在类定义中,当前类是类本身,因此在类定义中使用 def foo
定义的方法成为该类的实例方法。
但是当您使用 A
类作为接收器调用 instance_eval 时,根据上表,您将“当前类”更改为接收器的单例类;由于您使用 def
定义方法,因此它将在“当前类”中定义,从而产生“类方法”(在 A 的单例类或特征类中定义的方法):
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
定义方法时,根据上表,您实际上是在隐式接收器 define_method
上调用 self
;如果您查看表格,self
将是接收方 A
,因此它与调用 A.define_method
甚至:
class A
define_method(:method1) {}
end
这就是为什么,在这种情况下,您会得到一个实例方法,因为您在类 A 上调用了define_method,而不是在 A 的单例类(或也称为 eigenclass)中。