0

根据 Dave Thomas 在他关于 Ruby 对象模型的演讲中,Ruby中没有“类方法”。方法的接收者是“类对象”还是“实例对象”只有区别。

class Dave
  def InstaceMethod              ### will be stored in the current class (Dave)
    puts "Hi"
  end
  class << self                  ### Creates an eigenclass, if not created before
    def say_hello
      puts "Hello"
    end
  end
end

默认情况下,ancestors方法不显示元类:

class Dave
  class << self
    def metaclass                ### A way to show the hidden eigenclass
      class << self; self; end
    end
  end
end

p Dave.ancestors
# => [Dave, Object, Kernel, BasicObject]
p Dave.metaclass.ancestors
# => [Class, Module, Object, Kernel, BasicObject]

但是,我认为真正的应该是这样的:

# => [<eigenclass>, Class, Module, Object, Kernel, BasicObject]

p Dave.class.instance_method(false)
# => [:allocate, :new, :superclass]
p Dave.metaclass.instance_method(false)
# => [:say_hello, :metaclass]

现在继承。

class B < Dave
end

p B.say_hello
# => "Hello"
p B.ancestors
# => [B, Dave, Object, Kernel, BasicObject]
p B.class.instance_methods(false)
# => [:allocate, :new, :superclass]

以下将为 创建一个新的特征类B

p B.metaclass.ancestors
# => [Class, Module, Object, Kernel, BasicObject]
p B.metaclass.instance_method(false)
# => []
  1. 当特征类也包括在内时 和 会是什么样B.ancestors子?B.metaclass.ancestors该方法say_hello存储在一个特征类中,(我假设B.class继承自)但那在哪里?

  2. 由于有两个祖先链(B.ancestorsB.class.ancestorsB.metaclass.ancestors),继承实际上是如何发生的?

4

2 回答 2

3

一个对象(以及作为对象的类,Class 的实例)有一个指向其类的类字段。创建一个单例类(eigenclass/metaclass)会创建一个匿名类并将这个指针更改为指向匿名类,其类指针将指向原始类。该class方法不显示匿名类,只显示原始类。对于 mixins 也是一样。一个类有一个超类字段。该方法include创建一个匿名代理,超类指针被更改为指向匿名代理类,并从那里指向超类。该方法ancestors不显示匿名类,而是显示包含模块的名称。该superclass方法不显示匿名代理类,只显示原始超类。

您可以阅读以下内容:为什么 Ruby 中的符号不​​被视为一种变量?

在对此答案的评论中,有一个关于单例类的有趣文章的链接,可以在 Devalot 博客上找到。

人们需要一些时间来吸收这些继承链。由于一张好图值得长篇大论,我推荐The Pickaxe中的第 24 章元编程,其中有关于所有这些链的各种图片。

默认情况下,祖先方法不显示元类:
和 1. 当特征类也包括在内时,B.ancestors ... 会是什么样子?

ancestors涉及超类链。eigenclass 不属于超类链。

p Dave.metaclass.ancestors
=> [Class, Module, Object, Kernel, BasicObject]
但是,我认为真正的应该是这样的:
=> [ "eigenclass" , Class, Module, Object, Kernel, BasicObject]

正确的。

您可以简化您的 Dave 课程:

class Dave
    def self.say_hello    # another way to create an eigenclass, if not created before
      puts "Hello"
    end
    def self.metaclass    # A way to show the hidden eigenclass
        class << self
            self
        end
    end
end

Dave.say_hello           # => Hello
Dave.new.class.say_hello # => Hello
p Dave.metaclass.instance_methods(false) # => [:say_hello, :metaclass]
p Dave.singleton_methods                 # => [:say_hello, :metaclass]

def self.metaclass自从 Ruby 1.9.2 引入Object#singleton_class.

于 2013-01-04T10:07:53.093 回答
1

Eigenclass 是一个偷偷摸摸的隐藏类。你已经通过开课成功地揭示了它。但它并不存在于普通阶级的祖先中。而且由于它是隐藏的,因此您无法通过将ancestors方法发送到特征类本身来看到它。继承树如下:

B ---S-->  Dave   ---S---> Object  ---S---> BasicObject
|            |               |                  |
E            E               E                  E
|            |               |                  |
#B --S--> #Dave   ---S---> #Object ---S---> #BasicObject --S---> Class,,Object,BasicObject

S代表超类,而E代表本征类。

于 2013-01-04T09:39:06.313 回答