Rubyのシングルトンクラスとは何ですか?
概要
Rubyのeigenclassまたはsingletonクラスの概念を理解するのに苦労しています。 eigenclass はクラスのクラスであるとよく読みました。すべてのクラスが実際にはクラス Class のインスタンスであるため、私にとってクラスのクラスは実際には Class であるため、それは私には意味がありません。
私がよく理解できないもう 1 つの点は、次の文です。クラス メソッドは実際にはクラス eigenclass のインスタンス メソッドです。 eigenclass には次の方法でアクセスできます。
YourClass = Class.new
class << YourClass
def class_method
end
end
しかし、eigenclass が実際に YourClass クラス (つまり Class) である場合、前のコード部分でクラス Class を開き、それにインスタンス メソッド class_method を追加して、将来のすべてのインスタンス (通常のクラス) にアクセスできるようにすべきではないでしょうか。将来定義される)?
実際のところ、シングルトン クラスはクラスと同じではないような気がします。実行するとき:
class MyClass
end
MyClass.singleton_class
#
#
私の考えを明確にするために、eigenclass の概念についてのシンプルで明確な説明を探しています。
解決策
シングルトン クラスは、単一のオブジェクトに固有のメソッドを保持します。
一般的なオブジェクトにとって、これはあると便利な機能です。しかし、授業にとって、それは非常に重要です。オブジェクトから始めましょう:
インスタンス メソッドは通常、クラス内で定義されます。同じクラスのすべてのインスタンスは、同じインスタンス メソッドを共有します。シングルトン クラスは、オブジェクトとそのクラスの間に位置します。これにより、各インスタンスが他のインスタンスから独立した独自のメソッドのセットを持つことができます。
2 つのクラス Foo と Bar があり、それぞれ 2 つのインスタンス a、b、c、d があるとします。
class Foo ; end
class Bar ; end
a = Foo.new #=> #<Foo:0x00007fc280963008>
b = Foo.new #=> #<Foo:0x00007f8319016b18>
c = Bar.new #=> #<Bar:0x00007fa66c8d7290>
d = Bar.new #=> #<Bar:0x00007f94d5106ac8>
次のクラス構造になります: (モジュールを除いて簡略化)
object singleton class class superclass ...
a ── #<Class:#<Foo:0x00007fc280963008>> ─┐
├─ Foo ─┐
b ── #<Class:#<Foo:0x00007f8319016b18>> ─┘ │
├─ Object ── BasicObject
c ── #<Class:#<Bar:0x00007fa66c8d7290>> ─┐ │
├─ Bar ─┘
d ── #<Class:#<Bar:0x00007f94d5106ac8>> ─┘
Ruby は、たとえば、singleton_class を呼び出すときに、これらのシングルトン クラスを遅延して作成します。
したがって、メソッド a.hello を定義すると、そのメソッドは a のクラス Foo ではなく、 a のシングルトン クラスに格納されます。
def a.hello
'hello from a'
end
a.method(:hello).owner
#=> #<Class:#<Foo:0x00007fc280963008>> <-- a's singleton class
そのため、両方とも Foo インスタンスであるにもかかわらず、 b にはそのメソッドが表示されません。
b.hello #=> NoMethodError: undefined method `hello'
また、a に干渉することなく、b に同じ名前のメソッドを定義することもできます。
def b.hello
'hello from b'
end
b.method(:hello).owner
#=> #<Class:#<Foo:0x00007f8319016b18>> <-- b's singleton class
a.hello #=> "hello from a"
b.hello #=> "hello from b"
また、Foo で汎用 hello を定義し、それをインスタンス レベルでオーバーライドすることもできます (通常はこれを行いませんが、可能です)。
class Foo
def hello
'hello'
end
end
def a.hello
"#{super} from a"
end
def b.hello
"b says #{super.upcase}!"
end
a.hello #=> "hello from a"
b.hello #=> "b says HELLO!"
c = Foo.new
c.hello #=> "hello"
上記はクラスにとって特に重要です。各クラスは Class のインスタンスです。
Foo.class #=> Class
Foo.hello メソッドが必要だとします。それをどこで定義すればよいでしょうか?
インスタンス メソッドは通常、インスタンスのクラスで定義されるため、Foo のクラスで定義できます。
class Class
def hello
'Hello from Foo'
end
end
Foo.hello
#=> "Hello from Foo"
ただし、これにより、クラスのすべてのインスタンスでメソッドが使用できるようになります。
Bar.hello
#=> "Hello from Foo"
String.hello
#=> "Hello from Foo"
Foo インスタンス専用の場所があったほうがよいでしょう。そして、その場所は Foo のシングルトン クラスです。
def Foo.hello
'Hello from Foo'
end
または
class Foo
def self.hello # <-- self is Foo, so this is just "def Foo.hello"
'hello from Foo'
end
end
上記の a.hello と同様に、このメソッドは Foo のみが使用できます。
Foo.hello #=> "hello from Foo"
Bar.hello #=> NoMethodError
これらのメソッドをクラス メソッドと呼びますが、実際にはシングルトン クラスの単なるインスタンス メソッドです。
Foo.method(:hello).owner
#=> #<Class:Foo> <-- Foo's singleton class
Foo.method(:hello).unbind == Foo.singleton_class.instance_method(:hello)
#=> true
クラスのシングルトン メソッドとオブジェクトのシングルトン メソッドを比較すると、それらが同一であることがわかります。これは、Ruby ではクラスもオブジェクトであり、すべてのオブジェクトが同様に機能するためです。