classe << idioma próprio em Ruby


873

O que class << selffaz em Ruby ?


35
Há um artigo muito bom sobre este tópico escrito por Yehuda Katz: yehudakatz.com/2009/11/15/... e Yugui: yugui.jp/articles/846
Andrei

3
Outro artigo super legal aqui: integralist.co.uk/posts/eigenclass.html
Saman Mohamadi

2
Estou vendo isso dentro de um módulo, isso o torna diferente? github.com/ruby/rake/blob/master/lib/rake/rake_module.rb
William Entriken

@FullDecent Não faz diferença, pois tudo em Ruby é um objeto que inclui módulos e classes.
Aaron

Respostas:


912

Primeiro, a class << foosintaxe abre a fooclasse singleton (classe própria). Isso permite que você especialize o comportamento dos métodos chamados nesse objeto específico.

a = 'foo'
class << a
  def inspect
    '"bar"'
  end
end
a.inspect   # => "bar"

a = 'foo'   # new object, new singleton class
a.inspect   # => "foo"

Agora, para responder à pergunta: class << selfabre self's única classe, de modo que os métodos podem ser redefinidos para o atual selfobjeto (que dentro de um corpo de classe ou módulo é a classe ou módulo em si ). Normalmente, isso é usado para definir métodos de classe / módulo ("estático"):

class String
  class << self
    def value_of obj
      obj.to_s
    end
  end
end

String.value_of 42   # => "42"

Isso também pode ser escrito como uma abreviação:

class String
  def self.value_of obj
    obj.to_s
  end
end

Ou ainda mais curto:

def String.value_of obj
  obj.to_s
end

Quando dentro de uma definição de função, selfrefere-se ao objeto com o qual a função está sendo chamada. Nesse caso, class << selfabre a classe singleton para esse objeto; um uso disso é implementar a máquina de estado de um homem pobre:

class StateMachineExample
  def process obj
    process_hook obj
  end

private
  def process_state_1 obj
    # ...
    class << self
      alias process_hook process_state_2
    end
  end

  def process_state_2 obj
    # ...
    class << self
      alias process_hook process_state_1
    end
  end

  # Set up initial state
  alias process_hook process_state_1
end

Portanto, no exemplo acima, cada instância de StateMachineExampletem um process_hookalias process_state_1, mas observe como, no último, ele pode redefinir process_hook( selfapenas por não afetar outras StateMachineExampleinstâncias) para process_state_2. Portanto, cada vez que um chamador chama o processmétodo (que chama de redefinível process_hook), o comportamento muda dependendo do estado em que ele está.


22
@ Jörg: +1 para edição (eu desejo que o SO ofereça a capacidade de editar edições; tudo bem). Esse é realmente o uso mais comum de class << self, para criar métodos de classe / módulo. Provavelmente vou expandir esse uso de class << self, pois esse é um uso muito mais idiomático.
Chris Jester-Young

4
gsub! ("eigenclass", "singleton class"), consulte o próximo método redmine.ruby-lang.org/repositories/revision/1?rev=27022
Marc-André Lafortune

4
É realmente confuso para se referir a aé singleton_classdesde a's classe (após a mudança inspect) é uma variante única da Stringclasse. Se estivesse mudando a Stringclasse singleton , isso afetaria todas as outras Stringinstâncias. O mais estranho ainda é que se você reabrir mais tardeString para redefinir inspect, aainda assim receberá as novas alterações.
Old Pro

1
@ OldPro Eu ainda prefiro o nome de classe própria, como (acredito) Matz também. Mas, não posso agradar a todos, eu acho.
Chris Jester-Young

5
Acho a expressão "abre a classe singleton de um objeto" - que já li muitas vezes antes - vaga. Que eu saiba, em nenhum lugar nos documentos do Ruby está "abrindo" uma classe definida, mesmo que todos tenhamos uma idéia do que isso significa. Será que class << selfnada média mais do que o valor selfé definido igual à classe singleton dentro do escopo do bloco?
Cary Swoveland

34

Encontrei uma explicação super simples sobre class << self,Eigenclass e vários tipos de métodos.

No Ruby, existem três tipos de métodos que podem ser aplicados a uma classe:

  1. Métodos de instância
  2. Métodos Singleton
  3. Métodos de classe

Os métodos de instância e métodos de classe são quase semelhantes aos homônimos em outras linguagens de programação.

class Foo  
  def an_instance_method  
    puts "I am an instance method"  
  end  
  def self.a_class_method  
    puts "I am a class method"  
  end  
end

foo = Foo.new

def foo.a_singleton_method
  puts "I am a singletone method"
end

Outra maneira de acessar um Eigenclass (que inclui métodos singleton) é com a seguinte sintaxe ( class <<):

foo = Foo.new

class << foo
  def a_singleton_method
    puts "I am a singleton method"
  end
end

agora você pode definir um método singleton para o selfqual é a Fooprópria classe neste contexto:

class Foo
  class << self
    def a_singleton_and_class_method
      puts "I am a singleton method for self and a class method for Foo"
    end
  end
end

4
na verdade, os métodos Singleton e os métodos Class são os mesmos, ambos existentes na classe singleton. você pode usar foo.singleton_class.instance_methods(false)para verificar.
Damon Yuan

22

Geralmente, métodos de instância são métodos globais. Isso significa que eles estão disponíveis em todas as instâncias da classe em que foram definidas. Por outro lado, um método singleton é implementado em um único objeto.

Ruby armazena métodos em classes e todos os métodos devem ser associados a uma classe. O objeto no qual um método singleton é definido não é uma classe (é uma instância de uma classe). Se apenas classes podem armazenar métodos, como um objeto pode armazenar um método singleton? Quando um método singleton é criado, Ruby cria automaticamente uma classe anônima para armazenar esse método. Essas classes anônimas são chamadas de metaclasses, também conhecidas como classes singleton ou autoclasses. O método singleton está associado à metaclasse que, por sua vez, está associada ao objeto no qual o método singleton foi definido.

Se vários métodos singleton forem definidos em um único objeto, todos serão armazenados na mesma metaclasse.

class Zen
end

z1 = Zen.new
z2 = Zen.new

class << z1
  def say_hello
    puts "Hello!"
  end
end

z1.say_hello    # Output: Hello!
z2.say_hello    # Output: NoMethodError: undefined method `say_hello'…

No exemplo acima, a classe << z1 altera o self atual para apontar para a metaclasse do objeto z1; em seguida, define o método say_hello na metaclasse.

Classes também são objetos (instâncias da classe interna chamada Class). Os métodos de classe nada mais são do que métodos singleton associados a um objeto de classe.

class Zabuton
  class << self
    def stuff
      puts "Stuffing zabuton…"
    end
  end
end

Todos os objetos podem ter metaclasses. Isso significa que as classes também podem ter metaclasses. No exemplo acima, a classe << self modifica a si mesma, de modo que aponta para a metaclasse da classe Zabuton. Quando um método é definido sem um receptor explícito (a classe / objeto no qual o método será definido), ele é definido implicitamente no escopo atual, ou seja, o valor atual de self. Portanto, o método stuff é definido dentro da metaclasse da classe Zabuton. O exemplo acima é apenas outra maneira de definir um método de classe. IMHO, é melhor usar a sintaxe def self.my_new_clas_method para definir métodos de classe, pois isso facilita a compreensão do código. O exemplo acima foi incluído para que possamos entender o que está acontecendo quando encontramos a auto-sintaxe da classe <<.

Informações adicionais podem ser encontradas neste post sobre Ruby Classes .


15

Que classe << coisa faz:

class Hi
  self #=> Hi
  class << self #same as 'class << Hi'
    self #=> #<Class:Hi>
    self == Hi.singleton_class #=> true
  end
end

[faz self == thing.singleton_class no contexto de seu bloco] .


O que é o thing.singleton_class?

hi = String.new
def hi.a
end

hi.class.instance_methods.include? :a #=> false
hi.singleton_class.instance_methods.include? :a #=> true

hiherda objeto seus #methodsa partir da sua #singleton_class.instance_methodse, em seguida, a partir da sua #class.instance_methods.
Aqui demos hi's única classe método de instância :a. Poderia ter sido feito com a classe << oi .
hi's #singleton_classtem todos os métodos de instância hi' s #classtem, e, possivelmente, um pouco mais ( :aaqui).

[métodos de instância de coisa #class e #singleton_class podem ser aplicados diretamente a coisa. quando ruby ​​vê thing.a, primeiro procura: uma definição de método em thing.singleton_class.instance_methods e depois em thing.class.instance_methods]


A propósito - eles chamam a classe singleton do objeto == metaclass == eigenclass .


3

Um método singleton é um método definido apenas para um único objeto.

Exemplo:

class SomeClass
  class << self
    def test
    end
  end
end

test_obj = SomeClass.new

def test_obj.test_2
end

class << test_obj
  def test_3
  end
end

puts "Singleton's methods of SomeClass"
puts SomeClass.singleton_methods
puts '------------------------------------------'
puts "Singleton's methods of test_obj"
puts test_obj.singleton_methods

Métodos de SingClon de SomeClass

teste


Métodos de singleton de test_obj

test_2

test_3


1

De fato, se você escrever qualquer extensão C para seus projetos Ruby, na verdade, existe apenas uma maneira de definir um método Module.

rb_define_singleton_method

Eu sei que esse negócio próprio apenas abre todos os tipos de outras perguntas para que você possa fazer melhor pesquisando cada parte.

Objetos primeiro.

foo = Object.new

Posso criar um método para foo?

Certo

def foo.hello
 'hello'
end

O que eu faço com isso?

foo.hello
 ==>"hello"

Apenas outro objeto.

foo.methods

Você obtém todos os métodos Object, além do seu novo.

def foo.self
 self
end

foo.self

Apenas o objeto foo.

Tente ver o que acontece se você criar foo de outros objetos como classe e módulo. É bom brincar com os exemplos de todas as respostas, mas você precisa trabalhar com idéias ou conceitos diferentes para realmente entender o que está acontecendo com a maneira como o código é escrito. Então agora você tem muitos termos para analisar.

Singleton, Class, Module, self, Object e Eigenclass foram criados, mas Ruby não nomeia Object Models dessa maneira. É mais como Metaclass. Richard ou __por que mostra a idéia aqui. http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html E se você ficar impressionado, tente pesquisar o Ruby Object Model na pesquisa. Dois vídeos que eu conheço no YouTube são Dave Thomas e Peter Cooper. Eles também tentam explicar esse conceito. Dave demorou muito tempo para obtê-lo, então não se preocupe. Eu ainda estou trabalhando nisso também. Por que mais eu estaria aqui? Obrigado pela sua pergunta. Também dê uma olhada na biblioteca padrão. Possui um módulo Singleton, assim como um FYI.

Isso é muito bom. https://www.youtube.com/watch?v=i4uiyWA8eFk

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.