6

Ruby ではsuper、次のコードが示すように、シングルトン メソッド内で使用して、対応するスーパー クラスのシングルトン メソッドを呼び出すことができます。

class Base
  def self.class_method
    puts "Base class method"
  end
end

class Derived < Base
  def self.class_method
    puts "Derived class method"
    super
  end
end

Derived.class_method
# Derived class method
# Base class method

superただし、その呼び出しがwithinDerived.class_methodに到達する方法がよくわかりませんBase.class_method。メタクラスで定義されていると思いclass_methodますが、メタクラスに親子関係があるということですか? (実験で確かめることはできません)

更新: この質問をしているのは、基本クラスと派生クラスのメタクラスの間に何らかの関係があることをどこかで見たのを思い出したためです (しかし、それ以上は見つかりません)。実際にどのように機能するかを知ることに加えてsuper、2 つのメタクラスが完全に分離されているかどうかも確認したいと思います。

4

3 に答える 3

11

ここでは、4 つのクラス オブジェクトが使用されます。

<Class>---class---><Class>
Base               #Base
   ^                  ^
   |                  |
   |                  |
 super              super
   |                  |
   |                  |
<Class>            <Class>
Derived---class--->#Derived

命名法:

  • <...> は各オブジェクトのクラスです。
  • クラスの名前は 2 行目にあります。
  • 名前が # で始まる場合、それは固有クラス (別名シングルトン クラス) です。
  • クラスのスーパークラスへのスーパーポイント
  • class はクラスのクラスを指します。

Derived.class_method を呼び出すとき、Ruby は「右から上へ」という規則に従います。まずオブジェクトのクラスに移動し、次にスーパークラス チェーンを上にたどり、メソッドが見つかると停止します。

  • 「class_method」呼び出しの受信側は Derived です。そのため、その固有クラス (#Derived) である Derived のクラス オブジェクトへのチェーンをたどってください。
  • Derived はメソッドを定義しないため、Ruby は #Derived のスーパークラスである #Base までチェーンをたどります。

  • そこにメソッドがあるので、Ruby はメッセージを #Base.class_method にディスパッチします。

私が頭のてっぺんからこれらすべてを知っていたとは思いませんよね?これが私の脳がこのすべてのメタジュジュを取得した場所です: Metaprogramming Ruby

パート 2. 「固有クラス」(別名「シングルトン クラス」) を隠れ家から出現させる方法

class Object
  def eigenclass
    class << self
      self
    end
  end
end

このメソッドは、任意のオブジェクトの固有クラスを返します。さて、授業は?それらもオブジェクトです。

p Derived.eigenclass               # => #<Class:Derived>
p Derived.eigenclass.superclass    # => #<Class:Base>
p Base.eigenclass                  # => #<Class:Base>

注: 上記は Ruby1.9 のものです。Ruby 1.8 で実行すると、驚くべき結果が得られます。

p Derived.eigenclass.superclass    # => #<Class:Class>
于 2010-01-26T07:12:27.897 に答える
4

Rubyが固有クラスを非表示/公開する方法に関するコメントに書いたことを明確にして修正するために、次の状況があります。

Ruby 1.8:

(1)メソッドは常に、オブジェクトの実際のObject#classクラスの最初の実数(非固有クラスまたはiclass)スーパークラスを返します。例えば

o = Object.new
class << o; end
o.class #=> returns Object, even though the _actual_ class is the eigenclass of o

つまり、Object#classメソッドは固有クラスを返すことはなく、固有クラスを渡し、代わりに継承階層で最初に見つかった「実際の」クラスを返します。

(2)このClass#superclass方法には2つのケースがあります。受信者が固有クラスでない場合は、単にスーパークラスを返します。ただし、レシーバー固有クラスの場合、このメソッドはレシーバーの実際の(つまり必ずしも実際ではない)クラスを返します。

# case where receiver is a normal class (i.e not an eigenclass)
Module.superclass #=> Object (behaves as expected)

# case where receiver is an eigenclass
class << Module; superclass; end #=> returns Class, this is NOT the superclass

上記からClass#superclass、通常のクラスの場合は期待どおりに動作しますが、固有クラスの例では、モジュールの固有クラスのスーパークラスは真ではないクラスであると示されています。この図http://banisterfiend.wordpress.com/2008/10/25/the-secret-life-of-singletons/から、Moduleの固有クラスのスーパークラスが実際にはObjectの固有クラスであることがわかります。Ruby1.8がこの奇妙な振る舞いをする理由はわかりません。

Ruby 1.9:

(1)Object#classメソッドは1.8バージョンと同じように動作します。

(2)Class#superclassメソッドに2つのケースがなくなり、固有クラスを通常のクラスと同じように処理し、実際のスーパークラスを期待どおりに返すようになりました。

例えば

class << Module; superclass; end #=> #<Class:Object>
于 2010-01-26T13:02:34.363 に答える
3

この図は関係を説明しています: http://banisterfiend.wordpress.com/2008/11/25/a-complete-ruby-class-diagram/

また、固有クラスの複雑さをより詳しく説明している他の投稿もいくつかあります: http://www.klankboomklang.com/2007/10/05/the-metaclass/

http://www.klankboomklang.com/2007/09/21/the-singleton-class/

そして、ここにあなたがおそらく知りたい以上のことを説明するかなり難しいものがあります: http://banisterfiend.wordpress.com/2008/10/25/the-secret-life-of-singletons/

于 2010-01-26T07:59:43.343 に答える