论坛首页 入门技术论坛

令人迷惑的class_eval和instance_eval

浏览 8176 次
该帖已经被评为新手帖
作者 正文
   发表时间:2010-05-31   最后修改:2010-08-31

按照yugui 大姐的说法,class_eval和instance_eval有如下的区别:



class&instance_eval              self                            default definee
class_eval                          the receiver                   the receiver
instance_eval                   the receiver                     eigenclass of the receiver




上面就是class_eval与instance_eval的区别了,一般情况下这个没有问题(个人感觉)。但还是会有令迷惑的地方。
下面的例子说明了,在下面情况下,class_eval和instance_eval的作用没有区别。

class A
end
class Object
	def eigenclass
		class << self;self;end
	end
end
A.class_eval do
p self
	def hehe
		"hehe"
	end
	define_method(:xixi) do
		"xixi"
	end
end

A.instance_eval do
p self
	def haha;"haha";p self ;end
end

A.instance_eval do
p self
	define_method(:hihi) do
		"hihi"
		p self.to_s
	end
end
 
 A.haha
 A.new.hihi
 p A.instance_methods
 p  "*"*120
 p A.eigenclass.instance_methods

    定义的hihi和xixi都是A是实例方法。


 jayfield  
说到:

define_method always defines an instance method on the target (Foo in our example). This makes sense because define_method is being call on the implicit self, which evaluates to the receiver (Foo) in our example."[/

 


jayfield的说法应该是有问题的,但不这样理解,上面的例子怎么又说得通呢?



PS:可能是我表述不清还是怎么的,基本上没有人对此关注。实际上我想说的就是:

A.instance_eval do 
p self 
def haha;"haha";p self ;end 
end 

A.instance_eval do 
p self 
define_method(:hihi) do 
"hihi" 
p self.to_s 
end 
end 

 



   同样是用instance_eval,为什么有这么大的不同。

A.new.hihi 
A.haha 

 

事实上,

A.instance_eval do
p self
define_method(:hihi) do
"hihi"
p self.to_s
end
end

 

 

与 class A

 

  define_method(:hihi) do

     "hihi"

 

end

end

的效果是一样的,define_method是个私有方法,能调用(隐式)它的只能是类对象而非一般的对象。

 

 

 

 


  在一个网站 上看到了这个:

 

 

现在可以比较直观的理解这二者的不同了

 

  • 大小: 29.9 KB
   发表时间:2010-05-31  
define_method always defines an instance method on the target
0 请登录后投票
   发表时间:2010-06-01  
axgle 写道
define_method always defines an instance method on the target

A.instance_eval do 
p self 
     define_method(:hihi) do 
         "hihi" 
         p self.to_s 
    end 
end 
axgle说的是一般情况。上面这个例子就是定义了一个实例方法,如何解释?
0 请登录后投票
   发表时间:2010-06-04  

  1. A.instance_eval do  
  2. self  
  3.     def haha;"haha";p self ;end  
  4. end  
  5.   
  6. A.instance_eval do  
  7. self  
  8.     define_method(:hihido  
  9.         "hihi"  
  10.         p self.to_s  
  11.     end  
  12. end  

def 是ruby的关键字,他会定义方法到当前的ruby_class(一个隐藏的变量), instance_eval会改变ruby_class,使之成为receiver(A)的meta class(而class_eval则将其变为receiver),所以def定义的方法,就是A的方法(类方法)或者说是A的meta class的实例方法, define_method是ruby中Module的方法,用于定义self的实例方法,instance_eval不会改变self,所以hihi是A的实例方法。

0 请登录后投票
   发表时间:2010-06-04  
hf_cn81 写道

  1. A.instance_eval do  
  2. self  
  3.     def haha;"haha";p self ;end  
  4. end  
  5.   
  6. A.instance_eval do  
  7. self  
  8.     define_method(:hihido  
  9.         "hihi"  
  10.         p self.to_s  
  11.     end  
  12. end  

def 是ruby的关键字,他会定义方法到当前的ruby_class(一个隐藏的变量), instance_eval会改变ruby_class,使之成为receiver(A)的meta class(而class_eval则将其变为receiver),所以def定义的方法,就是A的方法(类方法)或者说是A的meta class的实例方法, define_method是ruby中Module的方法,用于定义self的实例方法,instance_eval不会改变self,所以hihi是A的实例方法。


instance_eval 肯定会改变self,无论是用def或者define_method这点可以保证的。
0 请登录后投票
   发表时间:2010-06-05   最后修改:2010-06-05

instance_eval里的self就是receiver,这和class_eval没有区别,所以

A.instance_eval do

puts self

end

 

A.class_eval do

puts self

end

打印的结果一样,但是instance_eval改变了“ruby_class”到A的meta class,而class_eval则将“ruby_class"改成A。

def定义的方法是做为”ruby_class“的实例方法,而define_method定义的方法是作为self的实例方法。

 

8 请登录后投票
   发表时间:2010-06-06  
hf_cn81 写道

instance_eval里的self就是receiver,这和class_eval没有区别,所以

A.instance_eval do

puts self

end

 

A.class_eval do

puts self

end

打印的结果一样,但是instance_eval改变了“ruby_class”到A的meta class,而class_eval则将“ruby_class"改成A。

def定义的方法是做为”ruby_class“的实例方法,而define_method定义的方法是作为self的实例方法。

 

 

 

照你的意思,instance_eval中应该有2个不同的self.一个是可以打印出来的的那个,一个就是更改后的ruby_class。对吗?

0 请登录后投票
   发表时间:2010-06-06  
我也困惑过。我也来谈谈。
instance_eval,名字上就有instance,就是实例。
什么是实例?a = A.new ,这个a就是实例。
我再自问一句,a实例是什么?
因为在ruby世界里什么都是对象,那个a这个对象其实就是A的单例。
所以你可以这样
def a.method1
   puts 'this is singleton method'
end

a.method1

所以也会有
class A
end

a = A.new
a.instance_eval do
  self  # => a
  # current class => a's singleton class
  def method1
    puts 'this is a singleton method of instance a'
  end
end

a.method1
#=> this is a singleton method of instance a

b = A.new
b.method1
#=>NoMethodError: undefined method `method1' for #<A:0x10043ff70>

我在想,Ruby是一个语言的大杂烩,不会像Python那样优雅,所以它一定是遵循一种简单的语义。所以我们不能像别其它语言那样,把高度看太高,其实想过来很简单。

coding in fun!
============
class_eval是为Class定义函数。
我知道只要在Class里定义的函数,它的实例就相应得到了这些函数。
class A
end

a = A.new
a.method1
#=> NoMethodError: undefined method `method1' for #<A:0x10043ff70>

A.class_eval do
  self  # => A
  # current class => A
  def method1
    puts 'this is a instance method of class A'
  end
end

a.method1
#=> this is a instance method of class A


参考:
http://note.jiaeil.com/2010/05/16/digging-ruby-instance_eval-and-class_eval/


0 请登录后投票
   发表时间:2010-08-31  
axgle 写道
define_method always defines an instance method on the target

关键问题是:这个target是指的什么
0 请登录后投票
   发表时间:2010-08-31  
target就是self吧
A.instance_eval{puts self}
A.class_eval{puts self}
出来的结果都是A
所以在这两个里面的define_method都是给A定义一个实例方法
instance_eval与class_eval只是给define_method提供了一个self环境
0 请登录后投票
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics