Cos'è esattamente la classe singleton in ruby?


85

La classe singleton in Ruby è una classe in sé e per sé? È il motivo per cui tutti gli oggetti appartengono alla "classe"? Il concetto è confuso , ma credo che abbia qualcosa a che fare con il motivo per cui posso definire un metodo di classe ( class foo; def foo.bar ...).

Qual è la classe singleton in Ruby?

Risposte:


154

Innanzitutto, una piccola definizione: un metodo singleton è un metodo definito solo per un singolo oggetto. Esempio:

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

I metodi di istanza sono metodi di una classe (ovvero definiti nella definizione della classe). I metodi di classe sono metodi singleton sull'istanza Classdi una classe: non sono definiti nella definizione della classe. Invece, sono definiti sulla classe singleton dell'oggetto.

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

Apri la classe singleton di un oggetto con la sintassi class << obj. Qui, vediamo che questa classe singleton è dove vengono definiti i metodi singleton:

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

Quindi un mezzo alternativo per aggiungere metodi singleton a un oggetto sarebbe definirli con la classe singleton dell'oggetto aperta:

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

In sintesi:

  • i metodi devono sempre appartenere a una classe (oppure: essere metodi di istanza di una classe)
  • i metodi normali appartengono alla classe in cui sono definiti (cioè sono metodi di istanza della classe)
  • i metodi di classe sono solo metodi singleton di un file Class
  • i metodi singleton di un oggetto non sono metodi di istanza della classe dell'oggetto; piuttosto, sono metodi di istanza della classe singleton dell'oggetto.

17
Sulla mia lapide dirà "RIP Ruby Singleton. I pistos hanno salvato la mia sanità mentale".
rmcsharry

1
@sawa Apprezzo l'intento delle tue modifiche, ma sento che cambiano un po 'troppo il significato e la comunicazione del mio post, quindi ho ripristinato le tue modifiche.
Pistos

33

Ruby fornisce un modo per definire metodi specifici per un particolare oggetto e tali metodi sono noti come metodi Singleton. Quando si dichiara un metodo singleton su un oggetto, Ruby crea automaticamente una classe per contenere solo i metodi singleton. La classe appena creata si chiama Singleton Class.


    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
La classe Singleton è una classe anonima specifica di un oggetto che viene automaticamente creata e inserita nella gerarchia di ereditarietà.

singleton_methods può essere chiamato su un oggetto per ottenere l'elenco dei nomi per tutti i metodi singleton su un oggetto.

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

Questo articolo mi ha davvero aiutato a capire le classi Singleton in Ruby e ha un buon esempio di codice.


4
Sebbene questa risposta abbia più di un anno e il collegamento sia utile, sarebbe meglio se pubblichi le parti essenziali della risposta qui, su questo sito, altrimenti il ​​tuo post rischia di essere cancellato Vedi le FAQ dove menziona risposte che sono 'appena più di un collegamento '. Puoi comunque includere il link se lo desideri, ma solo come "riferimento". La risposta dovrebbe stare da sola senza bisogno del collegamento.
Taryn

d'accordo con @bluefeet qui
Saurabh

Grazie @bluefeet, ha aggiornato la risposta per indirizzare il tuo commento.
Bedasso

7

Come solo aggiornamento alla risposta @Pistos, dalla versione 1.9.2 ruby ​​aggiunge una nuova sintassi per ottenere la classe singleton

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

può essere sostituito con:

singleton_class = foo.singleton_class

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


4

Il modo più pragmatico / basato sull'azione di pensarlo (IMHO) è: come una catena di ereditarietà o un ordine di ricerca / risoluzione del metodo. Questa immagine potrebbe aiutare

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

Questo è r 1.9, che contrasta le classi predefinite e definite dall'utente: sto ancora digerendo questo.

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

Inoltre, penso che un uso confuso del termine sia "oggetto Singleton", che è un concetto diverso. Un oggetto singleton proviene da una classe che ha il suo metodo costruttore / istante sovrascritto in modo da poter allocare solo una di quella classe.


Uno dei collegamenti è morto. E l'altro è giapponese!
Ulysse BN

0

Una classe singleton nei termini più semplici è una classe speciale che ruby ​​crea per ospitare metodi definiti su singoli oggetti. In ruby, è possibile definire metodi su singoli oggetti che sono unici per quell'oggetto da solo. Ad esempio, considera quanto segue di seguito

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>)

Come puoi vedere sopra, l'oggetto user1 non risponde al metodo "age" perché è un metodo singleton, un metodo definito in modo univoco sull'oggetto utente. Affinché ciò avvenga, ruby ​​crea una classe speciale, chiamata classe singleton o eigenclass, per ospitare questo metodo univoco. Puoi verificarlo procedendo come segue:

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

Puoi anche chiedere a ruby ​​se il metodo "age" si trova qui utilizzando l'oggetto metodo per scoprire dove è definito il metodo "age". Quando lo fai, vedrai che la classe singleton ha quel metodo.

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]

Si noti inoltre che, per quanto riguarda una classe singleton, i metodi singleton sono in realtà metodi di istanza.

user.singleton_methods == user_singleton_class.instance_methods(false) # true
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.