Ruby Language
Singleton-Klasse
Suche…
Syntax
- singleton_class = class << object; selbst ende
Bemerkungen
Singleton-Klassen haben nur eine Instanz: ihr entsprechendes Objekt. Dies kann durch Abfragen von Rubys ObjectSpace
überprüft werden:
instances = ObjectSpace.each_object object.singleton_class
instances.count # => 1
instances.include? object # => true
Mit <
können sie auch als Unterklassen der tatsächlichen Klasse des Objekts überprüft werden:
object.singleton_class < object.class # => true
Verweise:
Einführung
Ruby hat drei Arten von Objekten:
- Klassen und Module, die Instanzen der Klasse Class oder Class Module sind.
- Instanzen von Klassen.
- Singleton-Klassen.
Jedes Objekt hat eine Klasse, die seine Methoden enthält:
class Example
end
object = Example.new
object.class # => Example
Example.class # => Class
Class.class # => Class
Objekte selbst können keine Methoden enthalten, nur ihre Klasse kann. Mit Singleton-Klassen ist es jedoch möglich, jedem Objekt, einschließlich anderer Singleton-Klassen, Methoden hinzuzufügen.
def object.foo
:foo
end
object.foo #=> :foo
foo
ist für die Einzelklasse des object
. Andere Example
können nicht auf foo
antworten.
Ruby erstellt bei Bedarf Singleton-Klassen. Der Zugriff auf sie oder das Hinzufügen von Methoden zwingt Ruby dazu, sie zu erstellen.
Zugriff auf die Singleton-Klasse
Es gibt zwei Möglichkeiten, um die Einzelklasse eines Objekts abzurufen
-
singleton_class
Methode. - Singleton-Klasse eines Objekts erneut öffnen und sich
self
.
object.singleton_class
singleton_class = class << object
self
end
Zugriff auf Instanz- / Klassenvariablen in Singleton-Klassen
Singleton-Klassen teilen ihre Instanz- / Klassenvariablen mit ihrem Objekt.
class Example
@@foo = :example
end
def Example.foo
class_variable_get :@@foo
end
Example.foo #=> :example
class Example
def initialize
@foo = 1
end
def foo
@foo
end
end
e = Example.new
e.instance_eval <<-BLOCK
def self.increase_foo
@foo += 1
end
BLOCK
e.increase_foo
e.foo #=> 2
Blöcke schließen sich um ihr Instanz- / Klassenvariablenziel. Der Zugriff auf class_eval
oder Klassenvariablen mit einem Block in class_eval
oder instance_eval
ist nicht möglich. Das Übergeben eines Strings an class_eval
oder die Verwendung von class_variable_get
das Problem.
class Foo
@@foo = :foo
end
class Example
@@foo = :example
Foo.define_singleton_method :foo do
@@foo
end
end
Foo.foo #=> :example
Vererbung der Singleton-Klasse
Unterklassen auch Unterklassen Singleton-Klasse
class Example
end
Example.singleton_class #=> #<Class:Example>
def Example.foo
:example
end
class SubExample < Example
end
SubExample.foo #=> :example
SubExample.singleton_class.superclass #=> #<Class:Example>
Das Erweitern oder Einschließen eines Moduls erweitert die Singleton-Klasse nicht
module ExampleModule
end
def ExampleModule.foo
:foo
end
class Example
extend ExampleModule
include ExampleModule
end
Example.foo #=> NoMethodError: undefined method
Nachrichtenübertragung mit Singleton-Klasse
Instanzen enthalten niemals eine Methode, die nur Daten enthält. Wir können jedoch eine Einzelklasse für jedes Objekt definieren, einschließlich einer Instanz einer Klasse.
Wenn eine Nachricht an ein Objekt übergeben wird (die Methode wird aufgerufen), prüft Ruby zuerst, ob für dieses Objekt eine Singleton-Klasse definiert ist und ob sie auf diese Nachricht antworten kann. Andernfalls überprüft Ruby die Vorfahrenkette der Instanz-Klasse und geht darauf ein.
class Example
def foo
:example
end
end
Example.new.foo #=> :example
module PrependedModule
def foo
:prepend
end
end
class Example
prepend PrependedModule
end
Example.ancestors #=> [Prepended, Example, Object, Kernel, BasicObject]
e = Example.new
e.foo #=> :prepended
def e.foo
:singleton
end
e.foo #=> :singleton
Wiedereröffnung (Affen-Patching) Singleton-Klassen
Es gibt drei Möglichkeiten, eine Singleton-Klasse wieder zu öffnen
-
class_eval
für eine Singleton-Klasse verwenden. -
class <<
Block verwenden. - Mit
def
eine Methode direkt in der Singleton-Klasse des Objekts definieren
class Example
end
Example.singleton_class.class_eval do
def foo
:foo
end
end
Example.foo #=> :foo
class Example
end
class << Example
def bar
:bar
end
end
Example.bar #=> :bar
class Example
end
def Example.baz
:baz
end
Example.baz #=> :baz
Jedes Objekt verfügt über eine Singleton-Klasse, auf die Sie zugreifen können
class Example
end
ex1 = Example.new
def ex1.foobar
:foobar
end
ex1.foobar #=> :foobar
ex2 = Example.new
ex2.foobar #=> NoMethodError
Singleton-Klassen
Alle Objekte sind Instanzen einer Klasse. Das ist jedoch nicht die ganze Wahrheit. In Ruby hat jedes Objekt auch eine etwas versteckte Singleton-Klasse .
Dadurch können Methoden für einzelne Objekte definiert werden. Die Singleton-Klasse befindet sich zwischen dem Objekt selbst und seiner tatsächlichen Klasse. Daher sind alle darin definierten Methoden für dieses Objekt und nur für dieses Objekt verfügbar.
object = Object.new
def object.exclusive_method
'Only this object will respond to this method'
end
object.exclusive_method
# => "Only this object will respond to this method"
Object.new.exclusive_method rescue $!
# => #<NoMethodError: undefined method `exclusive_method' for #<Object:0xa17b77c>>
Das obige Beispiel könnte mit define_singleton_method
geschrieben define_singleton_method
:
object.define_singleton_method :exclusive_method do
"The method is actually defined in the object's singleton class"
end
Dies ist das gleiche wie das Definieren der Methode für die singleton_class
Klasse des object
:
# send is used because define_method is private
object.singleton_class.send :define_method, :exclusive_method do
"Now we're defining an instance method directly on the singleton class"
end
Vor der Existenz von singleton_class
als Teil der Ruby-Kern-API wurden Singleton-Klassen als Metaklassen bezeichnet und konnten über die folgende Sprache aufgerufen werden:
class << object
self # refers to object's singleton_class
end