Domanda

Stavo guardando il primo programma di metaprogrammazione ruby ??di prag dave. Ad un certo punto ha detto che ruby ??introduce "classi fantasma" quando aggiungi un metodo a una variabile di istanza. i.

animal = "cat"
def animal.speak
  puts "hola"
end
animal.speak       # => hola
animal.class       # => String

dog = "dog"

dog.speak          # Undefined method `speak' for "dog":String
String.send :speak # NoMethodError: undefined method `speak' for String:Class
animal.send :speak # hola

Dov'è davvero l'archivio del metodo speak? Se si tratta di una classe proxy invisibile, come possiamo accedere a quella classe proxy?

È stato utile?

Soluzione

Il metodo speak è memorizzato in una metaclasse (nota anche come eigenclass), quella che tu chiami una "classe proxy invisibile". In Ruby, le variabili di istanza non hanno spazio per memorizzare i metodi. Possono solo memorizzare variabili di istanza e la loro classe. Pertanto, quando si aggiunge un metodo a un'istanza, viene creata una metaclasse e inserita nella sua catena di classi. Per una migliore comprensione degli interni, consiglio questo articolo di Klank Boom Klang.

Per accedere alla meta classe, puoi fare quanto segue:

animal = "cat"
def animal.speak
  puts "hola"
end
animal.speak       # => hola
animal.class       # => String

metaclass = class << animal; self; end

metaclass.inspect                        # => #<Class:#<String:0x2c9c460>>
metaclass.instance_methods.index 'speak' # => 102
metaclass.class                          # => Class

Altri suggerimenti

Alcuni ppl lo chiamano " Singleton Class "

singleton_class = class << animal; self; end

E in realtà questa classe singleton è l'host per i metodi di classe in qualsiasi classe, controlla questo esempio, prima definendo la classe Foo con i metodi di classe 'hi' e 'bye':

class Foo
  def self.hi ; p "hi" ; end
  def self.bye ; p "bye" ; end
end
Foo.singleton_methods #=> ["hi","bye"]

Ora definiamo un metodo che restituisce la classe singleton per noi:

class Object
  def singleton_class 
     class << self
       self
     end
  end
end

Ora prova questo:

Foo.singleton_methods #=> ["bye", "hi"]
Foo.singleton_class.instance_methods(false) #=> ["bye", "hi"]
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top