Ruby 关于 class 和 eigenclass 之间的关系和区别

naitnix · 2012年09月20日 · 最后由 EricWJP 回复于 2017年06月01日 · 6503 次阅读

Ruby 中对象的实例变量 (instance_variable) 是放在对象中,而对象的方法 (instance_methods) 则是放在对象的类里。我们可以在 irb 里用下面的命令来验证:

» “abc”.methods == String.instance_methods

=> true

在 ruby 里所有都是对象,因此 String 应该也是对象,下面的命令也应该返回 true:

» String.methods == String.class.instance_methods

=> false

出乎意料,原因是 String 的 class 并不是 String.class。class 方法并不总是返回对象的真正的类。在 Ruby 中,对象真正的类是单例类,也可以叫 eigenclass,如果这个对象没有 eigenclass,它的类才是 class 方法返回的值。可以用下面的方式获得对象的 eigenclass:

» eigenclass = class « String

» self

» end

=> #Class:String

这时我们再比较两个对象的方法,看看是否一致:

» String.methods == eigenclass.instance_methods

=> true

什么时候对象有 eigenclass? 有 2 种情况,Ruby 为你自动生成和自己显式生成。

在声明一个 class 时,Ruby 就会自动为你生成这个 class 的 eigenclass,其他的对象 (比如说 module) 则需要显式生成。通过下面的例子可以看出。

» module A

» end

» class B

» end

» A.object_id

=> -610322468

» B.object_id

=> -610341868

» aeigenclass = class « A

» self

» end

=> #Class:A

» aeigenclass.object_id

=> -610367458

» beigenclass = class « B

» self

» end

=> #Class:B

» beigenclass.object_id

=> -610341878

» class B

» include A

» end

=> B

» aBeigenclass.object_id

=> -610341878 <== 在 class 中 include module 不会生成新的 eigenclass

在这里通过比较 object_id 的大小可以看出对象创建的顺序。B 是 class,它的 object_id 后面就是 B 的 eigenclass 的 object_id。而 A 是 module,它的 eigenclass 在显式赋值时才被创建。

以上的例子让我似乎明白 eigenclass 与 class 之间的关系了:一个对象的真正的类应该是它的 eigenclass,而 class 只有在 eigenclass 不存在的时候才会作为该对象的类。

以下的例子是《ruby 元编程》中的例子:

class C def a_method 'C#a_method()' end end

class D < C end

obj = D.new obj.a_method => 'C#a_method()'

d_eigen = class << obj self end

puts d_eigen.superclass #=> D

根据上面的例子,d_eigen 应该是 obj 的 eigenclass(真正的类),但是这个 eigenclass 居然是 D 类的子类

一个对象的 eigenclass 的超类是这个对象的类,一个类的 eigenclass 的超类是这个类的超类的 eigenclass

以上是我的理解,不知道理解的对不对,请各位指教。谢谢

今天刚读到 ruby 元编程中的这一节,看了 LZ 的解释更明白了些,但是有句话没看懂,118 页,每个 eigenclass 只有一个实例,并且不能被继承。 只有一个实例很好理解,不能被继承指的是?125 页的类图,类 C 的 eigenclass 不是继承于 Object 类的 eigenclass 吗?这不是前后矛盾了? @naitnix

#1 楼 @neverlandxy_naix

你理解的很对,这里的继承指的非那个继承. 事实上你所谓的那个 125 页 那个继承,不是让你直接用的。或者说你根本不用太关注的。他只是 Ruby 内部的一个约定,为了实现 类方法的继承。

String.methods == String.class.instance_methods => false 因为 String 是 Ruby 语言已经定义好的类,我认为可能是在定义 String 这个类的时候 Ruby 语言本身就为它定义了的特别的方法,比如try_convert ,其实 Array 也有这个方法,但是自定义的类就没有这个方法,所以我觉得这就有可能是导致结果为 false 的原因。

String.methods == eigenclass.instance_methods => true 这个你在文章中也说了,在创建类的同时就已经创建好了 eigenclass.

我认为每个对象都应该有自己的 eigenclass

一个类的 eigenclass 的超类是这个类的超类的 eigenclass BasicObject.singleton_class.superclass
=> Class 很奇怪!

#5 楼 @simlegate

因为 BasicObject 的超类的 singleton_class 就是它自身呀。

你是真的不会写文章 估计自己都读不明白

需要 登录 后方可回复, 如果你还没有账号请 注册新账号