classe << idioma di sé in Ruby


873

Cosa fa class << selfin Ruby ?


35
C'è un bell'articolo su questo argomento scritto da Yehuda Katz: yehudakatz.com/2009/11/15/… e Yugui: yugui.jp/articles/846
Andrei

3
Un altro articolo super bello qui: integralist.co.uk/posts/eigenclass.html
Saman Mohamadi

2
Lo vedo all'interno di un modulo, è diverso? github.com/ruby/rake/blob/master/lib/rake/rake_module.rb
William Entriken,

@FullDecent Non fa differenza poiché tutto in Ruby è un oggetto inclusi moduli e classi.
Aaron,

Risposte:


912

Innanzitutto, la class << foosintassi apre la fooclasse singleton (eigenclass). Ciò consente di specializzare il comportamento dei metodi chiamati su quell'oggetto specifico.

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

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

Ora, per rispondere alla domanda: class << selfapre la selfclasse singleton, in modo che i metodi possano essere ridefiniti per l' selfoggetto corrente (che all'interno di un corpo di classe o modulo è la classe o il modulo stesso ). Di solito, questo è usato per definire metodi di classe / modulo ("statici"):

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

String.value_of 42   # => "42"

Questo può anche essere scritto come una scorciatoia:

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

O ancora più breve:

def String.value_of obj
  obj.to_s
end

Quando all'interno di una definizione di funzione, si selfriferisce all'oggetto con cui viene chiamata la funzione. In questo caso, class << selfapre la classe singleton per quell'oggetto; un uso è quello di implementare la macchina statale di un uomo povero:

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

Quindi, nell'esempio sopra, ogni istanza di StateMachineExampleha una process_hookalias process_state_1, ma nota come in quest'ultima, può ridefinire process_hook( selfsolo per , non influenzare altre StateMachineExampleistanze) a process_state_2. Quindi, ogni volta che un chiamante chiama il processmetodo (che chiama ridefinibile process_hook), il comportamento cambia a seconda dello stato in cui si trova.


22
@Jörg: +1 per la modifica (vorrei che SO fornisse la possibilità di migliorare le modifiche; vabbè). Questo è sicuramente l'uso più comune di class << self, per creare metodi di classe / modulo. Espanderò probabilmente su quell'uso di class << self, poiché è un uso molto più idiomatico.
Chris Jester-Young,

4
gsub! ("eigenclass", "singleton class"), vedi il metodo imminente redmine.ruby-lang.org/repositories/revision/1?rev=27022
Marc-André Lafortune

4
E 'davvero di confusione per fare riferimento a a's singleton_classdal momento che a' s classe (dopo la modifica inspect) è una variante unica della Stringclasse. Se stesse cambiando la Stringclasse singleton , avrebbe effetto su tutte le altre Stringistanze. Cosa c'è di più strano ancora è che se in seguito riapre Stringa ridefinire inspectpoi asarà ancora raccogliere le nuove modifiche.
Vecchio Pro

1
@OldPro Preferisco ancora il nome eigenclass, come (credo) anche Matz. Ma non posso piacere a tutti, immagino.
Chris Jester-Young,

5
Trovo l'espressione "apre la classe singleton di un oggetto" - che ho letto molte volte prima - vaga. Per quanto ne sappia, in nessun punto dei documenti di Ruby si sta "aprendo" una classe definita, anche se tutti abbiamo un'idea di cosa significhi. Fa class << selfmedia qualcosa di più che il valore di selfè impostato uguale alla classe Singleton nel campo di applicazione del blocco?
Cary Swoveland,

34

Ho trovato una spiegazione semplice super-su class << self, Eigenclasse diversi tipi di metodi.

In Ruby, ci sono tre tipi di metodi che possono essere applicati a una classe:

  1. Metodi di istanza
  2. Metodi Singleton
  3. Metodi di classe

I metodi di istanza e i metodi di classe sono quasi simili al loro omonimo in altri linguaggi di programmazione.

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

Un altro modo di accedere a un Eigenclass(che include metodi singleton) è con la seguente sintassi ( class <<):

foo = Foo.new

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

ora puoi definire un metodo singleton per il selfquale è la classe Foostessa in questo contesto:

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
in realtà i metodi Singleton e i metodi Class sono gli stessi, entrambi esistenti nella classe singleton. puoi usare foo.singleton_class.instance_methods(false)per controllare.
Damon Yuan,

22

Di solito, i metodi di istanza sono metodi globali. Ciò significa che sono disponibili in tutte le istanze della classe in cui sono state definite. Al contrario, un metodo singleton è implementato su un singolo oggetto.

Ruby memorizza i metodi nelle classi e tutti i metodi devono essere associati a una classe. L'oggetto su cui è definito un metodo singleton non è una classe (è un'istanza di una classe). Se solo le classi possono memorizzare metodi, come può un oggetto memorizzare un metodo singleton? Quando viene creato un metodo singleton, Ruby crea automaticamente una classe anonima per memorizzare quel metodo. Queste classi anonime sono chiamate metaclassi, note anche come classi singleton o occhiali da vista. Il metodo singleton è associato alla metaclasse che, a sua volta, è associata all'oggetto su cui è stato definito il metodo singleton.

Se più metodi singleton sono definiti all'interno di un singolo oggetto, vengono tutti memorizzati nella stessa 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'…

Nell'esempio sopra, la classe << z1 modifica il sé corrente in modo che punti alla metaclasse dell'oggetto z1; quindi, definisce il metodo say_hello all'interno della metaclasse.

Le classi sono anche oggetti (istanze della classe integrata chiamata Class). I metodi di classe non sono altro che metodi singleton associati a un oggetto di classe.

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

Tutti gli oggetti possono avere metaclassi. Ciò significa che le classi possono anche avere metaclassi. Nell'esempio sopra, la classe << self modifica sé in modo che punti alla metaclasse della classe Zabuton. Quando un metodo viene definito senza un ricevitore esplicito (la classe / oggetto su cui verrà definito il metodo), viene implicitamente definito nell'ambito corrente, ovvero il valore corrente di sé. Quindi, il metodo stuff è definito all'interno della metaclasse della classe Zabuton. L'esempio sopra è solo un altro modo per definire un metodo di classe. IMHO, è meglio usare la sintassi def self.my_new_clas_method per definire i metodi di classe, in quanto semplifica la comprensione del codice. L'esempio sopra è stato incluso, quindi capiamo cosa sta succedendo quando ci imbattiamo nella classe << auto-sintassi.

Ulteriori informazioni sono disponibili in questo post sulle lezioni di Ruby .


15

Che classe << cosa fa:

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

[fa self == thing.singleton_class nel contesto del suo blocco] .


Che cos'è 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

hil'oggetto eredita il suo #methodsdal suo #singleton_class.instance_methodse quindi dal suo #class.instance_methods.
Qui abbiamo dato hiil metodo dell'istanza di classe singleton:a . Invece avrebbe potuto essere fatto con la classe << ciao .
hi's #singleton_classha tutti i metodi di istanza hi' s #classha, e forse alcuni più ( :aqui).

[metodi di istanza di cosa #class e #singleton_class possono essere applicati direttamente alla cosa. quando ruby ​​vede thing.a, cerca prima: una definizione del metodo in thing.singleton_class.instance_methods e poi in thing.class.instance_methods]


A proposito: chiamano la classe singleton dell'oggetto == metaclass == eigenclass .


3

Il metodo singleton è un metodo definito solo per un singolo oggetto.

Esempio:

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

I metodi di Singleton di SomeClass

test


I metodi di Singleton di test_obj

test_2

test_3


1

In effetti, se scrivi estensioni C per i tuoi progetti Ruby, c'è davvero solo un modo per definire un metodo Module.

rb_define_singleton_method

So che questo business autonomo apre solo tutti i tipi di altre domande in modo da poter fare meglio cercando ogni parte.

Prima gli oggetti.

foo = Object.new

Posso fare un metodo per foo?

Sicuro

def foo.hello
 'hello'
end

Cosa ci faccio?

foo.hello
 ==>"hello"

Solo un altro oggetto.

foo.methods

Ottieni tutti i metodi Object più il tuo nuovo.

def foo.self
 self
end

foo.self

Solo l'oggetto Foo.

Prova a vedere cosa succede se fai foo da altri oggetti come Class e Module. Gli esempi di tutte le risposte sono belli da giocare, ma devi lavorare con idee o concetti diversi per capire davvero cosa sta succedendo con il modo in cui il codice è scritto. Quindi ora hai molti termini da consultare.

Singleton, Class, Module, self, Object ed Eigenclass sono stati cresciuti, ma Ruby non nomina così i Object Model. È più simile a Metaclass. Richard o __why ti mostra l'idea qui. http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html E se ti colpisce, prova a cercare Ruby Object Model nella ricerca. Due video che conosco su YouTube sono Dave Thomas e Peter Cooper. Provano anche a spiegare questo concetto. Dave ha impiegato molto tempo per ottenerlo, quindi non preoccuparti. Ci sto ancora lavorando. Perché altrimenti dovrei essere qui? Grazie per la tua domanda Dai un'occhiata anche alla libreria standard. Ha un modulo Singleton proprio come un FYI.

Questo è abbastanza buono. https://www.youtube.com/watch?v=i4uiyWA8eFk

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.