Domanda
Com'è possibile che Ruby consenta implicitamente metodi di accesso alla classe al di fuori della classe?
Esempio:
class Candy
def land
homer
end
end
def homer
puts "Hello"
end
Candy.new.land #Outputs Hello
Soluzione
La definizione di " homer " Il metodo aggiunge il metodo alla classe Object. Non sta definendo una funzione gratuita.
La classe Candy eredita implicitamente da Object e quindi ha accesso ai metodi in Object. Quando chiami " homer " nella "terra" metodo, la risoluzione del metodo non riesce a trovare una definizione nella classe corrente, passa alla super classe, trova il metodo che hai aggiunto a Object e lo chiama.
Altri suggerimenti
Un modo semplice per scoprire cosa succede
-
Quali classi / moduli vengono cercati per risolvere i metodi utilizzati negli oggetti Candy?
p Candy.ancestors # = > [Candy, Object, Kernel]
-
Candy ha un metodo chiamato homer?
p Candy.instance_methods (false) .grep (" homer ") # = > []
p Candy.private_instance_methods (false) .grep (" homer ") # = > []
-
OK Candy non ha alcun metodo chiamato 'homer'.
-
Le novità della catena di ricerca (vedi 1) = > & Quot; oggetto "
-
L'oggetto ha un metodo chiamato " homer " ? p Object.instance_methods (false) .grep (" homer ") # = > []
p Object.private_instance_methods (false) .grep (" homer ") # = > [" homer "]
Candy ha Object nella sua catena di ricerca che a sua volta ha un metodo di istanza privato "homer" quindi la risoluzione del metodo ha successo
La dichiarazione def definisce sempre il metodo nella classe di qualunque sé sia al punto di definizione
-
Che cos'è self prima della definizione di homer?
p self # = > principale def homer mette " Ciao " fine
-
Quindi qual è il suo tipo?
p self.class # = > Oggetto
Ecco perché homer finisce su Object
Tecnicamente, la definizione del metodo homer
è in realtà sul modulo Kernel
che è mescolato in Object
, non su < code> Object direttamente. Quindi quando homer
non è una variabile locale o un metodo di istanza definito su Candy
, la catena di ereditarietà del metodo Ruby viene seguita attraverso Object
e quindi per il modulo misto Kernel
e quindi questo codice viene eseguito.
Modifica: Scusa, non so perché l'ho pensato. Sembra che il metodo viva davvero su Object
. Non sono sicuro che faccia troppa differenza nella pratica, ma avrei dovuto confermare le cose prima di pubblicare.
Ruby non ha funzioni fluttuanti. Ogni metodo appartiene a qualche oggetto. I metodi che def
al livello superiore stanno effettivamente diventando metodi di istanza della classe Object
. Poiché tutto è un Object
a un certo livello, tutti gli oggetti hanno accesso ai metodi di istanza di Object
.