eigenclassがself.classと非常に似ているのに、なぜ同等ではないのですか?

StackOverflow https://stackoverflow.com/questions/1630815

質問

メモをどこかで見逃してしまったので、これを説明していただければと思います。

オブジェクトの固有クラスがself.classと異なるのはなぜですか?

class Foo
  def initialize(symbol)
    eigenclass = class << self
      self
    end
    eigenclass.class_eval do
      attr_accessor symbol
    end
  end
end

固有クラスとclass.selfを同一視する論理の列は、かなり単純です:

class << selfは、インスタンスメソッドではなく、クラスメソッドを宣言する方法です。 def Foo.barへのショートカットです。

したがって、クラスオブジェクトへの参照内では、selfを返すことはFoo.classと同一である必要があります。これは、クラスメソッド/属性の定義のために<=>が<=>を<=>に設定するためです。

混乱しただけですか?または、これはRubyメタプログラミングの卑劣なトリックですか?

役に立ちましたか?

解決

class << selfは、単なるクラスメソッドの宣言方法ではありません(その方法で使用できます)。おそらく次のような使用方法を見たことがあるでしょう:

class Foo
  class << self
    def a
      print "I could also have been defined as def Foo.a."
    end
  end
end

これは機能し、def Foo.aと同等ですが、動作方法は少し微妙です。秘密は、そのコンテキストでselfがオブジェクトFooを参照し、そのクラスがClassの一意の匿名サブクラスであることです。このサブクラスは、def a eigenclass と呼ばれます。したがって、aは、Foo.aの固有クラスにfrobという新しいメソッドを作成し、通常のメソッド呼び出し構文Stringでアクセスできます。

では、別の例を見てみましょう:

str = "abc"
other_str = "def"

class << str
  def frob
    return self + "d"
  end
end

print str.frob # => "abcd"
print other_str.frob # => raises an exception, 'frob' is not defined on other_str

この例は最後の例と同じですが、最初はわかりにくいかもしれません。 strは、<=>クラスではなく、<=>の固有の匿名サブクラスである<=>の固有クラスで定義されます。したがって、<=>には<=>メソッドがありますが、一般に<=>のインスタンスにはありません。 Stringのメソッドをオーバーライドすることもできます(特定のトリッキーなテストシナリオで非常に便利です)。

これで、元の例を理解できるようになりました。 <=>のinitializeメソッド内で、<=>はクラス<=>ではなく、<=>の特定のインスタンスを参照します。その固有クラスは<=>のサブクラスですが、<=>ではありません。それができないか、2番目の例で見たトリックが機能しませんでした。したがって、例を続けるには:

f1 = Foo.new(:weasels)
f2 = Foo.new(:monkeys)

f1.weasels = 4 # Fine
f2.monkeys = 5 # Also ok
print(f1.monkeys) # Doesn't work, f1 doesn't have a 'monkeys' method.

これがお役に立てば幸いです。

他のヒント

最も単純な答え:固有クラスはインスタンス化できません。

class F
 def eigen
  class << self 
   self
  end
 end
end
F.new.eigen.new #=> TypeError: can't create instance of virtual class
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top