Was genau ist die Singleton-Klasse in Ruby?

85

Ist die Singleton-Klasse in Ruby eine Klasse für sich? Ist es der Grund, warum alle Objekte zur "Klasse" gehören? Das Konzept ist verschwommen , aber ich glaube, es hat etwas damit zu tun, warum ich überhaupt eine Klassenmethode definieren kann ( class foo; def foo.bar ...).

Was ist die Singleton-Klasse in Ruby?

Keyofnight
quelle

Antworten:

154

Zunächst eine kleine Definition: Eine Singleton-Methode ist eine Methode, die nur für ein einzelnes Objekt definiert ist. Beispiel:

irb(main):001:0> class Foo; def method1; puts 1; end; end
=> nil
irb(main):002:0> foo = Foo.new
=> #<Foo:0xb79fa724>
irb(main):003:0> def foo.method2; puts 2; end
=> nil
irb(main):004:0> foo.method1
1
=> nil
irb(main):005:0> foo.method2
2
=> nil
irb(main):006:0> other_foo = Foo.new
=> #<Foo:0xb79f0ef4>
irb(main):007:0> other_foo.method1
1
=> nil
irb(main):008:0> other_foo.method2
NoMethodError: undefined method `method2' for #<Foo:0xb79f0ef4>
        from (irb):8

Instanzmethoden sind Methoden einer Klasse (dh in der Definition der Klasse definiert). Klassenmethoden sind Singleton-Methoden für die ClassInstanz einer Klasse - sie sind in der Definition der Klasse nicht definiert. Stattdessen werden sie in der Singleton-Klasse des Objekts definiert.

irb(main):009:0> Foo.method_defined? :method1
=> true
irb(main):010:0> Foo.method_defined? :method2
=> false

Sie öffnen die Singleton-Klasse eines Objekts mit der Syntax class << obj. Hier sehen wir, dass in dieser Singleton-Klasse die Singleton-Methoden definiert sind:

irb(main):012:0> singleton_class = ( class << foo; self; end )
=> #<Class:#<Foo:0xb79fa724>>
irb(main):013:0> singleton_class.method_defined? :method1
=> true
irb(main):014:0> singleton_class.method_defined? :method2
=> true
irb(main):015:0> other_singleton_class = ( class << other_foo; self; end )
=> #<Class:#<Foo:0xb79f0ef4>>
irb(main):016:0> other_singleton_class.method_defined? :method1
=> true
irb(main):017:0> other_singleton_class.method_defined? :method2
=> false

Ein alternatives Mittel zum Hinzufügen von Singleton-Methoden zu einem Objekt besteht darin, sie bei geöffneter Singleton-Klasse des Objekts zu definieren:

irb(main):018:0> class << foo; def method3; puts 3; end; end
=> nil
irb(main):019:0> foo.method3
3
=> nil
irb(main):022:0> Foo.method_defined? :method3
=> false

Zusammenfassend:

  • Methoden müssen immer zu einer Klasse gehören (oder: Instanzmethoden einer Klasse sein)
  • Normale Methoden gehören zu der Klasse, in der sie definiert sind (dh Instanzmethoden der Klasse).
  • Klassenmethoden sind nur Singleton-Methoden von a Class
  • Singleton-Methoden eines Objekts sind keine Instanzmethoden der Klasse des Objekts. Sie sind vielmehr Instanzmethoden der Singleton-Klasse des Objekts.
Pistos
quelle
17
Auf meinem Grabstein steht "RIP Ruby Singleton. Pistos hat meine geistige Gesundheit gerettet."
rmcsharry
1
@sawa Ich schätze die Absicht Ihrer Änderungen, aber ich habe das Gefühl, dass sie die Bedeutung und Kommunikation meines Beitrags ein wenig zu sehr verändern, sodass ich Ihre Änderungen zurückgesetzt habe.
Pistos
32

Ruby bietet eine Möglichkeit, Methoden zu definieren, die für ein bestimmtes Objekt spezifisch sind. Diese Methoden werden als Singleton-Methoden bezeichnet. Wenn eine Singleton-Methode für ein Objekt deklariert wird, erstellt Ruby automatisch eine Klasse, die nur die Singleton-Methoden enthält. Die neu erstellte Klasse heißt Singleton-Klasse.


    foo = Array.new
    def foo.size
      "Hello World!"
    end
    foo.size  # => "Hello World!"
    foo.class # => Array
    #Create another instance of Array Class and call size method on it
    bar = Array.new
    bar.size  # => 0
Die Singleton-Klasse ist eine objektspezifische anonyme Klasse, die automatisch erstellt und in die Vererbungshierarchie eingefügt wird.

singleton_methods kann für ein Objekt aufgerufen werden, um die Liste der Namen für alle Singleton-Methoden für ein Objekt abzurufen.

    foo.singleton_methods  # => [:size]
    bar.singleton_methods  # => []

Dieser Artikel hat mir wirklich geholfen, Singleton-Klassen in Ruby zu verstehen, und er enthält ein gutes Codebeispiel.

Bedasso
quelle
4
Obwohl diese Antwort über ein Jahr alt ist und der Link hilfreich ist, ist es besser, wenn Sie die wesentlichen Teile der Antwort hier auf dieser Website veröffentlichen oder Ihr Beitrag möglicherweise gelöscht wird. Lesen Sie die FAQ, in der Antworten erwähnt werden, die kaum mehr sind als ein Link '. Sie können den Link weiterhin einfügen, wenn Sie dies wünschen, jedoch nur als 'Referenz'. Die Antwort sollte für sich allein stehen, ohne den Link zu benötigen.
Taryn
stimme @bluefeet hier zu
Saurabh
Danke @bluefeet, habe die Antwort aktualisiert, um deinen Kommentar zu adressieren.
Bedasso
7

Fügen Sie ab Version 1.9.2 Ruby eine neue Syntax hinzu, um die Singleton-Klasse zu erhalten

 singleton_class = ( class << foo; self; end )

kann ersetzt werden durch:

singleton_class = foo.singleton_class

https://apidock.com/ruby/Object/singleton_class

Piotr Galas
quelle
4

Die pragmatischste / aktionsorientierteste Art, dies zu betrachten (IMHO), ist: als Vererbungskette oder Reihenfolge der Methodensuche / -auflösung. Dieses Bild könnte helfen

http://www.klankboomklang.com/2007/11/25/modules-part-i-enter-the-include-class/

Dies ist R 1.9, im Gegensatz zu eingebauten und benutzerdefinierten Klassen: Ich verdaue diese noch.

http://d.hatena.ne.jp/sumim/20080111/p1

Ich denke auch, dass eine verwirrende Verwendung des Begriffs "Singleton-Objekt" ist, was ein anderes Konzept ist. Ein Singleton-Objekt stammt aus einer Klasse, deren Konstruktor / Instantiator-Methode überschrieben wurde, sodass Sie nur eine dieser Klassen zuweisen können.

Gene T.
quelle
Einer der Links ist tot. Und der andere ist Japaner!
Ulysse BN
0

Eine Singleton-Klasse ist im einfachsten Sinne eine spezielle Klasse, die Ruby-Host-Methoden für einzelne Objekte erstellt. In Ruby ist es möglich, Methoden für einzelne Objekte zu definieren, die nur für dieses Objekt eindeutig sind. Betrachten Sie zum Beispiel das Folgende unten

class User; end
user = User.new
def user.age
  "i'm a unique method"
end
user1 = User.new 
user.age #"i'm a unique method"
user1.age # NoMethodError (undefined method `age' for #<User:0x0000559c66ab7338>)

Wie Sie oben sehen können, reagiert das Objekt user1 nicht auf die Methode 'age', da es sich um eine Singleton-Methode handelt, eine Methode, die für das Benutzerobjekt eindeutig definiert ist. Zu diesem Zweck erstellt Ruby eine spezielle Klasse, die als Singleton-Klasse oder Eigenklasse bezeichnet wird, um diese einzigartige Methode zu hosten. Sie können dies überprüfen, indem Sie folgende Schritte ausführen:

user.singleton_class # #<Class:#<User:0x0000559c66b47c58>>

Sie können Ruby auch fragen, ob die Methode 'age' hier gefunden wird, indem Sie mithilfe des Methodenobjekts herausfinden, wo die Methode 'age' definiert ist. Wenn Sie dies tun, werden Sie sehen, dass die Singleton-Klasse diese Methode hat.

user_singleton_class = user.method(:age).owner # #<Class:#<User:0x0000559c66b47c58>>
user.method(:age).owner == user.singleton_class # true
user_singleton_class.instance_methods(false) # [:age]

Beachten Sie auch, dass Singleton-Methoden für eine Singleton-Klasse tatsächlich Instanzmethoden sind.

user.singleton_methods == user_singleton_class.instance_methods(false) # true
Paa Yaw
quelle