¿Qué es exactamente la clase singleton en ruby?

85

¿Es la clase singleton en Ruby una clase en sí misma? ¿Es la razón por la que todos los objetos pertenecen a la "clase"? El concepto es difuso , pero creo que tiene algo que ver con por qué puedo definir un método de clase ( class foo; def foo.bar ...).

¿Cuál es la clase singleton en Ruby?

keyofnight
fuente

Respuestas:

154

Primero, una pequeña definición: un método singleton es un método que se define solo para un solo objeto. Ejemplo:

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

Los métodos de instancia son métodos de una clase (es decir, definidos en la definición de la clase). Los métodos de clase son métodos singleton en la Classinstancia de una clase; no están definidos en la definición de la clase. En cambio, se definen en la clase singleton del objeto.

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

Abre la clase singleton de un objeto con la sintaxis class << obj. Aquí, vemos que esta clase singleton es donde se definen los métodos 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

Entonces, un medio alternativo de agregar métodos singleton a un objeto sería definirlos con la clase singleton del objeto abierta:

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

En resumen:

  • los métodos siempre deben pertenecer a una clase (o: ser métodos de instancia de alguna clase)
  • los métodos normales pertenecen a la clase en la que están definidos (es decir, son métodos de instancia de la clase)
  • Los métodos de clase son solo métodos singleton de un Class
  • Los métodos singleton de un objeto no son métodos de instancia de la clase del objeto; más bien, son métodos de instancia de la clase singleton del objeto.
Pistos
fuente
17
En mi lápida dirá "RIP Ruby Singleton. Pistos salvó mi cordura".
rmcsharry
1
@sawa Aprecio la intención de tus ediciones, pero siento que cambian demasiado el significado y la comunicación de mi publicación, así que he revertido tus ediciones.
Pistos
33

Ruby proporciona una forma de definir métodos que son específicos de un objeto en particular y dichos métodos se conocen como métodos Singleton. Cuando uno declara un método singleton en un objeto, Ruby crea automáticamente una clase para contener solo los métodos singleton. La clase recién creada se llama Clase Singleton.


    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 clase Singleton es una clase anónima específica de objeto que se crea e inserta automáticamente en la jerarquía de herencia.

singleton_methods se puede llamar en un objeto para obtener la lista de nombres para todos los métodos singleton en un objeto.

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

Este artículo realmente me ayudó a comprender las clases Singleton en Ruby y tiene un buen ejemplo de código.

Bedasso
fuente
4
Si bien esta respuesta tiene más de un año y el enlace es útil, sería mejor si publica las partes esenciales de la respuesta aquí, en este sitio, o su publicación corre el riesgo de ser eliminada. Consulte las preguntas frecuentes donde menciona respuestas que son 'apenas más que un enlace '. Aún puede incluir el enlace si lo desea, pero solo como 'referencia'. La respuesta debe mantenerse por sí sola sin necesidad del enlace.
Taryn
de acuerdo con @bluefeet aquí
Saurabh
Gracias @bluefeet, actualizó la respuesta para abordar su comentario.
Bedasso
7

Como acaba de actualizar a la respuesta de @Pistos, desde la versión 1.9.2 ruby ​​agregue una nueva sintaxis para obtener la clase singleton

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

se puede reemplazar con:

singleton_class = foo.singleton_class

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

Piotr Galas
fuente
4

La forma más pragmática / basada en la acción de pensarlo (en mi humilde opinión) es: como una cadena de herencia, o un orden de búsqueda / resolución de métodos. Esta imagen puede ayudar

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

Esto es r 1.9, contrastando las clases integradas y definidas por el usuario: todavía estoy digiriendo esta.

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

Además, creo que un uso confuso del término es "Objeto Singleton", que es un concepto diferente. Un objeto singleton proviene de una clase que tiene su método constructor / instanciador anulado para que pueda asignar solo uno de esa clase.

Gen T
fuente
Uno de los enlaces está muerto. ¡Y el otro es japonés!
Ulysse BN
0

Una clase singleton en los términos más simples es una clase especial que ruby ​​se adapta a métodos de host definidos en objetos individuales. En ruby, es posible definir métodos en objetos individuales que son exclusivos de ese objeto solo. Por ejemplo, considere lo siguiente a continuación

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

Como puede ver arriba, el objeto user1 no responde al método 'age' porque es un método singleton, un método definido de forma única en el objeto del usuario. Para que esto suceda, ruby ​​crea una clase especial, llamada clase singleton o clase propia, para alojar este método único. Puede verificar esto haciendo lo siguiente:

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

También puede preguntarle a ruby ​​si el método 'edad' se encuentra aquí utilizando el objeto de método para averiguar dónde está definido el método 'edad'. Cuando hagas esto, verás que la clase singleton tiene ese método.

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]

También tenga en cuenta que, en lo que respecta a una clase singleton, los métodos singleton son en realidad sus métodos de instancia.

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