10
class << self 
attr_accessor :n, :totalX, :totalY 
end 

La sintassi precedente viene utilizzata per definire le variabili di istanza di classe. Ma quando penso a ciò che la sintassi implica, non ha alcun senso per me, quindi mi chiedo se questo tipo di sintassi venga usato per altri tipi di definizioni. Il mio punto di confusione qui è questo:In Ruby sono presenti le applicazioni correlate della sintassi: class << self ... end

class << self 

L'operatore accodamento normalmente significa "aggiungere ciò che è a destra per l'oggetto a sinistra". Ma nel contesto di questo blocco, come si aggiunge "a mettere il contenuto di questo blocco nella definizione dell'istanza di classe piuttosto che dell'istanza"?

Per lo stesso motivo sono confusa sul motivo per cui in un contesto classe < < sé può definire variabili istanza di classe, mentre in un altro sembra per creare variabili di classe come ad esempio qui:

class Point 
    # Instance methods go here 
    class << self 
    # Class methods go here 
    end 
end 

risposta

18

in Ruby è possibile riaprire classi esistenti e aggiungere metodi. Cioè, si può dire:

class Foo 
    def bob 
    return "hello from bob" 
    end 
end 

questi metodi vengono memorizzati da qualche parte in un dizionario interno (forse una variabile di istanza) del Foo di classe (che è solo un esempio del Class di classe e quindi ha variabili di istanza)

Ma la cosa sorprendente è che è anche possibile aggiungere metodi per casi degli oggetti esistenti

foo = Foo.new 
foo2 = Foo.new 

def foo.fred 
    return "I am fred" 
end 


foo.fred #=> "I am fred" 
foo2.fred #=> NoMethodError 

ma Dove viene effettivamente memorizzato questo metodo?

Risulta Rubino crea una nuova classe dietro le quinte (talvolta chiamato classe singleton, metaclasse o eigenclass) che viene inserito nella gerarchia di ereditarietà tra la Foo di classe e la sua istanza.

Quindi la relazione di ereditarietà sembra che:

foo < (eigenclass of foo) < Foo < Class 

(se dici foo.superclasse non vedrai la classe singleton)

il class << X -syntax è un modo per arrivare a questa classe speciale, in modo che tu possa manipolarlo direttamente. I seguenti blocchi di codice sono esattamente equivalenti:

def foo.bar 
    return "xy" 
end 

# is exactly the same as 

class << foo 
    def bar 
    return "xy" 
    end 
end 

Quindi la somiglianza tra class Foo < Bar e class << Foo non è casuale, c'è l'eredità in corso in entrambi.

Pensate class << X come "aprire la metaclasse di X"

La cosa da ricordare in Ruby è che le classi stesse sono solo oggetti. (Le istanze della classe Class) quindi se dicono:

class Foo 
    class << self 
    def k 
     return "x" 
    end 
    end 
end 

(self è destinata a Foo in questo blocco di codice) in modo k è un metodo esempio dei eigenclass di Foo, il che lo rende un metodo di classe per Foo

tutto questo è spiegato più chiaramente nel chapter about classes of the Pickaxe (la versione web non contiene gli schemi, purtroppo) e _whys Seeing Metaclasses Clearly

2

Pensate al class come contenente un dizionario di membri compresi tutti gli accessors e le variabili di istanza. Quando dici alla classe di "aggiungere" a "sé", stai dicendo "aggiungi questi al dizionario dei membri della classe".

Acconsento che la notazione sia un po 'strana, però.

+0

Ok - che' s un buon modo di guardare - la classe è in realtà un dizionario. Ma in realtà hai risposto prima di aggiungere il mio ultimo esempio, dove in un altro contesto la stessa sillaba (secondo il libro che sto leggendo) produce metodi di classe invece di metodi di istanza di classe. Perché l'esempio di classe Point in basso restituisce un metodo di classe mentre l'attr_accessor in alto fornisce attributi che si trovano a livello di istanza di classe? –

+0

Utilizzando effettivamente la spiegazione che hai dato forse posso rispondere alla domanda nel mio commento precedente - il metodo attr_accessor chiama i metodi instance_variable_set e instance_variable_get della classe Class. Normalmente, quelli risulterebbero in variabili di istanza che vengono create, ma poiché stiamo aggiungendo al dizionario di classe, mentre lo inseriamo, stiamo creando variabili di istanza di classe. Ok, penso di averlo capito ora. Grazie. –

+1

-1 fuorviante, poiché la classe << x ... end in realtà aggiunge informazioni al metaclasse di x, non alla classe di x. – rampion

1

in realtà è confuso pensarlo in termini di un operatore "append". un modo migliore di vederlo è che proprio come class Foo si apre la classe Foo, cioè si imposta 'self' sull'oggetto classe Foo, creando se necessario, quindi class << self apre l'eigenclass dell'oggetto "self" corrente. si noti che non è limitato all'auto: per qualsiasi barra degli oggetti, è possibile pronunciare la classe < < per aprire l'eigenclass di tale oggetto.

class A 
    def hello 
    print "hello world" 
    end 
end 

a = A.new 
b = A.new 

class << a 
    def goodbye 
    print "goodbye cruel world" 
    end 
end 

a.hello 
b.hello 
a.goodbye 
b.goodbye 
Problemi correlati