11

まず第一に、この質問は現実世界には当てはまらないことを理解しています。ただ興味があるだけです。

シングルトン メソッドを持つクラスがあるとします。

class Foo
    def self.bar
    end
end

を呼び出すとFoo.bar、最初に の各祖先のシングルトン クラスでメソッドが検索され、次にメソッドとその祖先Fooによって参照されるクラスが検索されます。.classで確認できFoo.singleton_class.ancestorsます。これは次を返します。

[#<Class:Foo>, #<Class:Object>, #<Class:BasicObject>,
 Class, Module, Object, Kernel, BasicObject]

しかし、次のようなネストされたシングルトン クラスがある場合はどうなるでしょうか。

class Foo
  class << self
    class << self
      def bar
      end
    end
  end
end

を呼び出すとFoo.singleton_class.singleton_class.ancestors、以下が返されます。

[#<Class:#<Class:Foo>>, #<Class:#<Class:Object>>,
 #<Class:#<Class:BasicObject>>, #<Class:Class>, #<Class:Module>,
 #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]

この階層がどのように編成されているかわかりません。

4

2 に答える 2

19

この説明の大部分は、James Coglan によるHow Ruby Method Dispatch Worksに基づいています。Ruby Hacking Guideの一部と、ソースのほんの一部です。

要約すると、祖先は次のようになります。

                                                           +----------------+
                                                           |                |
+--------------------------- Module ~~~~~~~~~~~~~~> #<Class:Module>         |
|                              ^                           ^                |
|                              |                           |                |
|                            Class ~~~~~~~~~~~~~~~> #<Class:Class>          |
|                              ^                           ^                |
|                              |                           |                |
| BasicObject ~~~~~> #<Class:BasicObject> ~~> #<Class:#<Class:BasicObject>> |
|     ^                        ^                           ^                |
|     |        Kernel          |                           |                |
|     |          ^             |                           |                |
|     |          |             |   +-----------------------|----------------+
|     +-----+----+             |   |                       |
|           |                  |   v                       |
+-------> Object ~~~~~~> #<Class:Object> ~~~~~~~~> #<Class:#<Class:Object>>
            ^                  ^                           ^
            |                  |                           |
           Foo ~~~~~~~~> #<Class:Foo> ~~~~~~~~~~> #<Class:#<Class:Foo>>

---> Parent
~~~> Singleton class

最初から始めて構築しましょう。BasicObjectはすべてのルートです。チェックするBasicObject.superclassと、 が得られnilます。BasicObjectのインスタンスでもありますClass。はい、それは循環します。コードにはそれを処理する特別なケースがありますAが のインスタンスである場合、BA.singleton_classの子であるため、次のBようになります。

                           Class
                             ^
                             |
BasicObject ~~~~~> #<Class:BasicObject>

Objectから継承しBasicObjectます。Aから継承する場合BAは の子でBありA.singleton_class、 の子ですB.singleton_classObjectも含まれKernelます。Aが含まれている場合B、は(それ自体の後、 の前に)Bの最初の祖先として挿入されます。AAA.superclass

                           Class
                             ^
                             |
BasicObject ~~~~~> #<Class:BasicObject
    ^                        ^
    |        Kernel          |
    |          ^             |
    |          |             |
    +-----+----+             |
          |                  |
        Object ~~~~~~> #<Class:Object>

KernelのインスタンスですModule。これは私たちが目にする唯一のインスタンスでModuleあり、そのシングルトン クラスはどの祖先チェーンにも表示されないため、それ以上の説明はしません。

これはFooから継承されObjectます (ただし、 と書く必要はありません< Object)。何Fooとそのシングルトン クラスの子であるかは、既に把握できています。

                           Class
                             ^
                             |
BasicObject ~~~~~> #<Class:BasicObject>
    ^                        ^
    |        Kernel          |
    |          ^             |
    |          |             |
    +-----+----+             |
          |                  |
        Object ~~~~~~> #<Class:Object>
          ^                  ^
          |                  |
         Foo ~~~~~~~~> #<Class:Foo>

Classが から継承されModule、 が からModule継承されるようになったため、と適切なシングルトン クラスObjectを追加します。ととModule、これは図面が少しファンキーになる場所です。をヒットするたびに、上へのトラバースを停止することを忘れないでください。Module < ObjectObject < BasicObjectBasicObject.instance_of?(Class)BasicObject

                                                           +----------------+
                                                           |                |
+--------------------------- Module ~~~~~~~~~~~~~~> #<Class:Module>         |
|                              ^                           ^                |
|                              |                           |                |
|                            Class ~~~~~~~~~~~~~~~> #<Class:Class>          |
|                              ^                                            |
|                              |                                            |
| BasicObject ~~~~~> #<Class:BasicObject>                                   |
|     ^                        ^                                            |
|     |        Kernel          |                                            |
|     |          ^             |                                            |
|     |          |             |   +----------------------------------------+
|     +-----+----+             |   |
|           |                  |   v
+-------> Object ~~~~~~> #<Class:Object>
            ^                  ^
            |                  |
           Foo ~~~~~~~~> #<Class:Foo>

最後のステップ。のすべてのインスタンスにClassは がありますsingleton_class(ただし、必要になるまでインスタンス化されません。そうしないと、より多くの RAM が必要になります)。シングルトン クラスはすべて のインスタンスでClassあるため、シングルトン クラスがあります。次の文に注意してください: クラスのシングルトン クラスの親は、クラスの親のシングルトン クラスです。型システムに関する限り、それを簡潔に述べる方法があるかどうかはわかりませんが、Ruby のソースは、どのような場合でも一貫性のためにそれを行っているだけだと言っています。したがって、 を要求するFoo.singleton_class.singleton_classと、言語は喜んで義務付け、必要な親を上に伝播し、最終的には次のようになります。

                                                           +----------------+
                                                           |                |
+--------------------------- Module ~~~~~~~~~~~~~~> #<Class:Module>         |
|                              ^                           ^                |
|                              |                           |                |
|                            Class ~~~~~~~~~~~~~~~> #<Class:Class>          |
|                              ^                           ^                |
|                              |                           |                |
| BasicObject ~~~~~> #<Class:BasicObject> ~~> #<Class:#<Class:BasicObject>> |
|     ^                        ^                           ^                |
|     |        Kernel          |                           |                |
|     |          ^             |                           |                |
|     |          |             |   +-----------------------|----------------+
|     +-----+----+             |   |                       |
|           |                  |   v                       |
+-------> Object ~~~~~~> #<Class:Object> ~~~~~~~~> #<Class:#<Class:Object>>
            ^                  ^                           ^
            |                  |                           |
           Foo ~~~~~~~~> #<Class:Foo> ~~~~~~~~~~> #<Class:#<Class:Foo>>

このグラフの任意のノードから開始し、深さ優先で右から左にトラバースすると (そして で停止するとBasicObject、希望どおりにノードの祖先チェーンが得られます。そして、いくつかの基本的な公理から構築したので、信頼が欠けている場合、構造をさらに検証する興味深い方法がいくつかあります。

node.singleton_class.ancestors - node.ancestorsグラフ内の任意のノードを探してみてください。これにより、ノード自体の祖先ではないシングルトン クラスの祖先が得られ、リスト内の紛らわしい冗長性の一部が排除されます。

> Foo.singleton_class.singleton_class.ancestors - Foo.singleton_class.ancestors
 => [#<Class:#<Class:Foo>>, #<Class:#<Class:Object>>, #<Class:#<Class:BasicObject>>,
     #<Class:Class>, #<Class:Module>]

を使用して、任意の 1 つの親を確認することもできますnode.superclass

> Foo.singleton_class.singleton_class.superclass
 => #<Class:#<Class:Object>>

また、オブジェクト ID がすべて一貫していることを確認することもできるため、互いに特定の関係を持たない匿名クラスがいたるところに出現することはありません。

> def ancestor_ids(ancestors)
>   ancestors.map(&:object_id).zip(ancestors).map{|pair| pair.join("\t")}
> end

> puts ancestor_ids(Foo.ancestors)
70165241815140  Foo
70165216040500  Object
70165216040340  Kernel
70165216040540  BasicObject

> puts ancestor_ids(Foo.singleton_class.ancestors)
70165241815120  #<Class:Foo>
70165216039400  #<Class:Object>
70165216039380  #<Class:BasicObject>
70165216040420  Class
70165216040460  Module
70165216040500  Object # Same as Foo from here down
70165216040340  Kernel
70165216040540  BasicObject

> puts ancestor_ids(Foo.singleton_class.singleton_class.ancestors)
70165241980080  #<Class:#<Class:Foo>>
70165215986060  #<Class:#<Class:Object>>
70165215986040  #<Class:#<Class:BasicObject>>
70165216039440  #<Class:Class>
70165216039420  #<Class:Module>
70165216039400  #<Class:Object> # Same as Foo.singleton_class from here down
70165216039380  #<Class:BasicObject>
70165216040420  Class
70165216040460  Module
70165216040500  Object
70165216040340  Kernel
70165216040540  BasicObject

そして、一言で言えば、それはあなたがオタクを狙撃する方法です.

于 2015-08-07T05:18:31.910 に答える
3

#<Class:Foo>特定のクラスの固有/匿名クラスFooです。この固有/匿名クラスも拡張されている場合は、別の固有クラスが作成されているため、次のように表されます。#<Class:#<Class:Foo>>

固有クラスの親はクラスの固有クラスでObjectあり、その親は の固有クラスですBasicObject。同様に、別の固有クラスの固有クラスの親は、そのクラスの固有クラスの固有クラスですObject

以下のコードとこの説明を組み合わせると、より多くの洞察が得られます

p Foo.class
p Foo.class.ancestors
puts "-----------------"
p Foo.singleton_class
p Foo.singleton_class.ancestors
puts "-----------------"
p Foo.singleton_class.singleton_class
p Foo.singleton_class.singleton_class.ancestors

出力する

Class
[Class, Module, Object, Kernel, BasicObject]
-----------------
#<Class:Foo>
[#<Class:Foo>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]
-----------------
#<Class:#<Class:Foo>>
[#<Class:#<Class:Foo>>, #<Class:#<Class:Object>>, #<Class:#<Class:BasicObject>>, #<Class:Class>, #<Class:Module>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]

上記の固有クラス階層は、任意の数のレベルまで繰り返されます。例えば:

p Foo.singleton_class.singleton_class.singleton_class.singleton_class.singleton_class
puts "-----------------"
p Foo.singleton_class.singleton_class.singleton_class.singleton_class.singleton_class.ancestors

上記のコード出力

#<Class:#<Class:#<Class:#<Class:#<Class:Foo>>>>>
-----------------
[#<Class:#<Class:#<Class:#<Class:#<Class:Foo>>>>>, #<Class:#<Class:#<Class:#<Class:#<Class:Object>>>>>, #<Class:#<Class:#<Class:#<Class:#<Class:BasicObject>>>>>, #<Class:#<Class:#<Class:#<Class:Class>>>>, #<Class:#<Class:#<Class:#<Class:Module>>>>, #<Class:#<Class:#<Class:#<Class:Object>>>>, #<Class:#<Class:#<Class:#<Class:BasicObject>>>>, #<Class:#<Class:#<Class:Class>>>, #<Class:#<Class:#<Class:Module>>>, #<Class:#<Class:#<Class:Object>>>, #<Class:#<Class:#<Class:BasicObject>>>, #<Class:#<Class:Class>>, #<Class:#<Class:Module>>, #<Class:#<Class:Object>>, #<Class:#<Class:BasicObject>>, #<Class:Class>, #<Class:Module>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]
于 2015-08-06T18:49:10.113 に答える