eigenclassがself.classと非常に似ているのに、なぜ同等ではないのですか?
-
06-07-2019 - |
質問
メモをどこかで見逃してしまったので、これを説明していただければと思います。
オブジェクトの固有クラスが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
Yehuda Katzは<!> quot; Rubyでのメタプログラミング:すべては自己について <!> quot;