O que exatamente é a classe única em rubi?

85

A classe singleton em Ruby é uma classe em si mesma? É por isso que todos os objetos pertencem à "classe"? O conceito é confuso , mas acredito que tenha algo a ver com o motivo pelo qual posso definir um método de classe ( class foo; def foo.bar ...).

Qual é a classe singleton em Ruby?

keyofnight
fonte

Respostas:

154

Primeiro, uma pequena definição: um método singleton é um método que é definido apenas para um único objeto. Exemplo:

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

Métodos de instância são métodos de uma classe (ou seja, definidos na definição da classe). Os métodos de classe são métodos singleton na Classinstância de uma classe - eles não são definidos na definição da classe. Em vez disso, eles são definidos na classe singleton do objeto.

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

Você abre a classe singleton de um objeto com a sintaxe class << obj. Aqui, vemos que esta classe singleton é onde os métodos singleton são definidos:

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

Portanto, um meio alternativo de adicionar métodos singleton a um objeto seria defini-los com a classe singleton do objeto aberta:

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

Em suma:

  • métodos devem sempre pertencer a uma classe (ou: ser métodos de instância de alguma classe)
  • métodos normais pertencem à classe em que estão definidos (ou seja, são métodos de instância da classe)
  • métodos de classe são apenas métodos singleton de um Class
  • os métodos singleton de um objeto não são métodos de instância da classe do objeto; em vez disso, eles são métodos de instância da classe singleton do objeto.
Pistos
fonte
17
Na minha lápide estará escrito "RIP Ruby Singleton. Pistos salvou minha sanidade."
rmcsharry
1
@sawa Agradeço a intenção de suas edições, mas sinto que elas mudaram um pouco demais o significado e a comunicação de minha postagem, por isso revirei suas edições.
Pistos
33

Ruby fornece uma maneira de definir métodos que são específicos para um objeto particular e tais métodos são conhecidos como Métodos Singleton. Quando alguém declara um método singleton em um objeto, Ruby cria automaticamente uma classe para conter apenas os métodos singleton. A classe recém-criada é chamada de Classe 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
A classe Singleton é uma classe anônima específica do objeto que é criada automaticamente e inserida na hierarquia de herança.

singleton_methods pode ser chamado em um objeto para obter a lista de nomes de todos os métodos singleton em um objeto.

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

Este artigo realmente me ajudou a entender as classes Singleton em Ruby e tem um bom exemplo de código.

Bedasso
fonte
4
Embora esta resposta tenha mais de um ano e o link seja útil, seria melhor se você postar as partes essenciais da resposta aqui, neste site, ou sua postagem corre o risco de ser excluída. Veja o FAQ onde menciona respostas que são 'pouco mais do que um link '. Você ainda pode incluir o link se desejar, mas apenas como uma 'referência'. A resposta deve ser independente, sem precisar do link.
Taryn
concordo com @bluefeet aqui
Saurabh
Obrigado @bluefeet, atualizou a resposta para endereçar seu comentário.
Bedasso de
7

Apenas atualize para a resposta @Pistos, a partir da versão 1.9.2 ruby ​​adiciona uma nova sintaxe para obter a classe singleton

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

pode ser substituído por:

singleton_class = foo.singleton_class

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

Piotr Galas
fonte
4

A maneira mais pragmática / orientada para a ação (IMHO) é: como uma cadeia de herança ou ordem de resolução / pesquisa de método. Esta imagem pode ajudar

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

Este é o r 1.9, contrastando as classes internas e definidas pelo usuário: ainda estou digerindo este.

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

Além disso, acho que um uso confuso do termo é "objeto Singleton", que é um conceito diferente. Um objeto singleton vem de uma classe que tem seu método construtor / instanciador sobrescrito para que você possa alocar apenas um dessa classe.

Gene T
fonte
Um dos links está morto. E o outro é japonês!
Ulysse BN
0

Uma classe singleton nos termos mais simples é uma classe especial que o ruby ​​leva para métodos hospedeiros definidos em objetos individuais. Em ruby, é possível definir métodos em objetos individuais que são exclusivos daquele objeto sozinho. Por exemplo, considere o seguinte

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 você pode ver acima, o objeto user1 não responde ao método 'age' porque é um método singleton, um método definido exclusivamente no objeto do usuário. Para que isso aconteça, o ruby ​​cria uma classe especial, chamada classe singleton, ou eigenclass, para hospedar esse método único. Você pode verificar isso fazendo o seguinte:

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

Você também pode perguntar a ruby ​​se o método 'age' é encontrado aqui usando o objeto de método para descobrir onde o método 'age' está definido. Ao fazer isso, você verá que a classe singleton tem esse 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]

Observe também que, no que diz respeito a uma classe de singleton, os métodos de singleton são, na verdade, seus métodos de instância.

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