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


Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow