Ruby 求解 singleton_class, singleton_methods 的深入问题

breeze · 2016年11月29日 · 最后由 jude 回复于 2016年12月03日 · 1313 次阅读

环境: ruby2.3.2

问题:
  1. 为什么下面两者的ancestors差这么多,A 与 A.singleton_class 有哪些关联与不同?
  2. 与 A.ancestors相比 A.singleton_class.ancestors中 #<Class:A>, #<Class:Object>类似这些东西是什么 ?
class A
end

A.ancestors
# => [A, Object, Kernel, BasicObject]

A.singleton_class.ancestors
# => [#<Class:A>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject] 
问题:
  1. 为什么不是一个 singleton_class 也可以定义singleton_method ?
  2. 现在可以推出,A 与 A.singleton_class 是完全不同的东西,那么 A.singleton_class 存在的意义是什么?
class A
  def self.say
    p 'say'
  end
end

A.singleton_methods
# => [:say]

A.singleton_class.singleton_methods
# => [:constants, :nesting]   方法中没有:say,这个可以理解,因为它的ancestors中没有A。

A.singleton_class?
#  => false

A.singleton_class.singleton_class?
#  => true
问题:
  1. 如果说 A.say是一个singleton_method,也是一个类方法, 那么 a1.run 是一个singleton_method,也是一个类方法?
  2. 类方法与singleton_method 有什么关系与不同?
class A
  def self.say
    p 'say'
  end
end

A.singleton_methods
# => [:say]

a1 = A.new

def a1.run
  p 'run'
end

a1.singleton_methods
# => [:run] 
问题:
  1. #<Class:#<A:0x000000010ac200>> 这是什么东西?实例变量也是一个类?
class A
  def self.say
    p 'say'
  end
end

a1 = A.new
#  => #<A:0x000000010ac200>

a1.singleton_class.ancestors
#=> [#<Class:#<A:0x000000010ac200>>, A, Object, Kernel, BasicObject]

a1.singleton_class.singleton_methods
#  => [:say]  # 因为ancestor中有 A, 所以继承了:say方法
共收到 8 条回复

In Ruby, everything is an object.

在ruby中类既是对象也是一个类, 对你第一个问题A.ancestore针对的是A.new出来的对象的祖先链。A.Singleton_class.ancestors针对的是A这个类对象的祖先链。问题二:那些在ruby里面叫元类,ruby里面的类都有元类。 A.singleton_class里面定义的是A这个类的方法。 a1.run这个方法是a1的单件方法,他是在a1的元类里面定义的。最后一个表示的是一个对象的元类ruby必看书"ruby元编程"还有新出的书"ruby源码剖析"

要了解单件,建议先学javascript

理解“类”也是一个对象是关键

class A; end
等价于
A = Class.new # 看到了么?创建一个“类”跟创建一个对象 ( a = A.new ) 是一样的

#4楼 @piecehealth 你们说的这些,我都懂,感觉和问题但无关。
就像A是 Class.new出来的对象,和 A.singleton_class 也是 Class.new出来的对象。
但是 A 与 A.singleton_class有什么相同 与 不同点呢?

#5楼 @breeze 你Class.new一个A.singleton_class看看

理解singleton_class的话应该站在对象的角度思考,这是一个专属于某个实例的特殊对象 用来描述这个实例的类方法

尝试回答一下:

1.为什么下面两者的ancestors差这么多,A 与 A.singleton_class 有哪些关联与不同?
2.与 A.ancestors相比 A.singleton_class.ancestors中 #<Class:A>, #<Class:Object>类似这些东西是什么 ?

首先要明白 ancestors 返回的是一个类的祖先链上的其他类(也包含自身),通过不断地调用 supercalss 方法就能遍历祖先链(例外情况是 Kernel ):

A.superclass #=> Object
Object.superclass #=> BasicObject
BasicObject.superclass #=> nil

然后要明白 singleton_class 是什么东西。它是一个隐藏在对象(不管是普通对象还是类)后面的一个特殊类,它只有一个实例(就是它自己)。既然 singleton_class 是一个类,那么调用它的 ancestors 方法就会返回它祖先链上的其他类。

A.singleton_class.superclass #=> #<Class:Object>
A.singleton_class.superclass.superclass #=> #<Class:BasicObject>

#<Class:Object> 其实就是 Object 这个类的 singleton_class 。

直到 Object 为止,一个类的 ancestors 跟它的 singleton_class 的 ancestors 是一一对应的,但是:

BasicObject.singleton_class.superclass #=> Class 
Class.superclass #=> Module
Module.superclass #=> Object
Object.superclass #=> BasicObject
BasicObject.superclass #=> nil

所以一个类的 singleton_class 的祖先链会比这个类的祖先链要长。

一个对象的 singleton_class 跟这个对象的关联,我觉得是 singleton_class 用来保存定义在对象身上的方法(这是 singleton_class 存在的意义);不同之处在于,如果这个对象是普通对象,它是不能保存方法的,如果这个对象是类,它可以保存类的实例方法;不管何种情况,它的 singleton_class 保存的都是定义在对象身上的方法。

1.为什么不是一个 singleton_class 也可以定义singleton_method ?

只要是个对象,都可以定义它的 singleton_method 方法。定义的方式有下面几种,实际效果都是一样的:

# 直接在对象上定义

class A; end
def A.p; puts 'A'; end
a = A.new
def a.p; puts 'a'; end

# 在类中定义(1)
class A
  def self.p; p 'A'; end
end
# 在类中定义(2)
class A
  def A.p; p 'A'; end
end
# 在类中定义(3)
class A
  class << self
    def p; p 'A'; end
  end
end

ps. 其他问题好像都已经顺便解释了。。。强烈建议看看《Ruby 元编程》这本书,看完就弄明白这些问题了。

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