14

rubyのすべてのクラスがメタクラスClassのインスタンスであることを理解しています。そして、その「通常の」オブジェクトは、これらのクラスのインスタンス(メタクラスクラスのインスタンス)です。

しかし、私は不思議に思っています。つまり、クラスはオブジェクトのルートであり、クラスはそれ自体がClassのインスタンスです(インスタンスがクラスであるため、メタクラスと呼ばれます)。いくつかのブログnewで、クラスClassのメソッドのオーバーライドを見ました。

したがって、Classはクラスとして動作しますが、そのインスタンスはクラスです。つまり、円があるように見えます。クラスClassはそれ自体のインスタンスのようです。

私は明らかにここでポイントを逃しています。クラスクラスの起源は何ですか?

これが私を混乱させる例です:

class Class
  def new
    #something
  end
end

ただし、keywordclassはクラスClassのインスタンスを意味します。では、これはどのように機能しますか?

4

4 に答える 4

34

これはどのように機能しますか

簡単:そうではありません。とにかく、Rubyではありません。

他のほとんどの言語と同様に、単に存在すると想定されるコアエンティティがいくつかあります。それらは空から落ち、薄い空気から実体化し、魔法のように現れます。

Rubyでは、これらの魔法のいくつかは次のとおりです。

  • Objectスーパークラスはありませんが、スーパークラスのないクラスを定義することはできません。暗黙の直接スーパークラスは常にObjectです。[注:の実装定義のスーパークラスが存在する可能性がありますがObject、最終的には、スーパークラスを持たないスーパークラスが存在することになります。]
  • ObjectのインスタンスでありClass、のサブクラスですObject(つまり、間接的にそれ自体ObjectのインスタンスですObject
  • ClassのサブクラスでありModule、のインスタンスです。Class
  • ClassのインスタンスですClass

これらのことはどれもRubyでは説明できません。

BasicObject、、およびすべてはObject、循環依存関係があるため、同時に存在する必要があります。ModuleClass

この関係をRubyコードで表現できないからといって、Ruby言語仕様がそうしなければならないと言えないわけではありません。これを行う方法を見つけるのは実装者次第です。結局のところ、Rubyの実装には、プログラマーとしてのあなたが持っていないオブジェクトへのアクセスのレベルがあります。

たとえば、Ruby実装は最初にを作成し、そのポインタとそのポインタBasicObjectの両方をに設定できます。superclassclassnull

次に、を作成し、ポインタをObjectに設定し、ポインタsuperclassをに設定します。BasicObjectclassnull

次に、を作成し、ポインタをModuleに設定し、ポインタsuperclassをに設定します。Objectclassnull

最後に、を作成し、ポインタをClassに設定し、ポインタsuperclassをに設定します。Moduleclassnull

BasicObjectこれで、を指すように's 、Object' s、Module's、およびClass'のclassポインタを上書きできます。これでClass完了です。

これはシステムの外部から簡単に実行でき、内部からは奇妙に見えます。

ただし、それら存在すると、それらの動作のほとんどをプレーンなRubyで実装することは完全に可能です。Rubyのオープンクラスのおかげで、これらのクラスの非常に必要最低限​​のバージョンのみが必要です。不足している機能は後で追加できます。

あなたの例では、class Classはという名前の新しいクラスを作成していません。ランタイム環境から提供された既存のクラスClassを再度開いています。Class

したがって、Class#newプレーンなRubyでのデフォルトの動作を説明することは完全に可能です。

class Class
  def new(*args, &block)
    obj = allocate # another magic thing that cannot be explained in Ruby
    obj.initialize(*args, &block)
    return obj
  end
end

[注:実際にinitializeはプライベートであるため、アクセス制限を回避するために使用する必要がありobj.send(:initialize, *args, &block)ます。]

ところで:Class#allocateそれらの魔法のもう一つです。これは、Rubyのオブジェクトスペースに新しい空のオブジェクトを割り当てます。これは、Rubyでは実行できないことです。したがって、Class#allocateランタイムシステムによっても提供される必要があるものです。

于 2012-05-10T00:30:14.173 に答える
4

「ツイスト」リンクによって与えられるメタ循環があります。これは、ルートの固有クラスからクラスへの組み込みのスーパークラスリンクClassです。これは次のように表すことができます

BasicObject.singleton_class.superclass == Class

マップを理解するための手がかり.classは、このマップが固有クラスとスーパークラスのリンクから派生していることです。オブジェクトの場合xx.classは固有クラスのスーパークラスチェーンの最初のクラスxです。これは次のように表すことができます

x.class == x.eigenclass.superclass(n)

ここで、は (即時値の問題に耐性eigenclassのある)の「概念エイリアス」であり、の-番目のスーパークラスを意味し、クラスであるような最小のものです。同様に、のスーパークラスチェーン内の固有クラスはスキップされます(rb_class_realを参照してください。これは、MRIでは、リンクも間接的に実装されていることを示しています。これらは「iclasses」をスキップすることによって発生します)。これにより、すべてのクラス(およびすべての固有クラス)のが常にクラスになります。singleton_classy.superclass(i)iynx.eigenclass.superclass(n)x.eigenclasssuperclassclassClass

写真はこの図によって提供されます。

メタクラスの混乱には、主に2つの原因があります。

  • Smalltalk。Smalltalk-80オブジェクトモデルには、Rubyオブジェクトモデルによって修正された概念上の不整合が含まれています。さらに、Smalltalkの文献では、用語で弁証法が使用されていますが、残念ながら、Rubyの文献では十分に改善されていません。

  • メタクラスの定義。現在、定義では、メタクラスはクラスのクラスであると述べられています。ただし、いわゆる「暗黙のメタクラス」(RubyおよびSmalltalk-80の場合)の場合、クラスのメタオブジェクトの定義がはるかに適切になります。

于 2012-05-11T19:11:56.323 に答える
3

はい、クラスはそれ自体のインスタンスです。これは、クラスのインスタンスでもあるModuleのサブクラスであり、Moduleは、ClassのインスタンスでもあるObjectのサブクラスです。それは確かにかなり循環的です—しかし、これはコア言語の一部であり、ライブラリの何かではありません。Rubyランタイム自体には、Rubyコードを書いているときにあなたや私がするのと同じ制限はありません。

しかし、クラスについて話すときに使用される「メタクラス」という言葉は聞いたことがありません。Rubyではあまり使用されていませんが、使用されている場合は、通常、正式に「オブジェクトのシングルトンクラス」と呼ばれるものの同義語であり、Object-Module-Classの三角形よりもさらに紛らわしいトピックです。

于 2012-05-10T00:29:56.500 に答える
2

少し古くなっていますが、_whyによるこの記事は動作を理解するのに役立つかもしれません。PaoloPerrottaのMetaprogrammingRubyで、このテーマについてさらに深く掘り下げることができます。

于 2012-05-10T00:10:13.703 に答える