Variabile di istanza: self vs @


179

Ecco un po 'di codice:

class Person
  def initialize(age)
    @age = age
  end

  def age
    @age
  end

  def age_difference_with(other_person)
    (self.age - other_person.age).abs
  end

  protected :age
end

Quello che voglio sapere è la differenza tra l'utilizzo @agee self.agenel age_difference_withmetodo.

Risposte:


260

La scrittura @ageaccede direttamente alla variabile di istanza @age. La scrittura self.agedice all'oggetto di inviare se stesso il messaggio age, che di solito restituirà la variabile di istanza @age, ma potrebbe fare qualsiasi numero di altre cose a seconda di come ageviene implementato il metodo in una determinata sottoclasse. Ad esempio, potresti avere una classe MiddleAgedSocialite che riporta sempre la sua età di 10 anni più giovane di quanto non sia in realtà. O più praticamente, una classe PersistentPerson potrebbe leggere pigramente quei dati da un archivio persistente, memorizzare tutti i dati persistenti in un hash.


2
Una volta ho letto un libro su rotaie e non capisco la differenza tra questo io e @, quindi dovrei sempre usare self.var_name nei miei metodi (che non si incastra e getter) per rendere i miei dati usando l'interfaccia pubblica, io trascorso del tempo a definirlo in getter e setter, giusto?
Sarunw,

1
... inglese ... cosa intendi con un numero qualsiasi di cose. non ho ricevuto gli ultimi due esempi.
user2167582

23

La differenza è che sta isolando l'uso del metodo dalla sua attuazione. Se l'implementazione della proprietà dovesse cambiare - diciamo per mantenere la data di nascita e quindi calcolare l'età in base alla differenza temporale tra ora e la data di nascita - allora il codice a seconda del metodo non deve cambiare. Se utilizzava direttamente la proprietà, la modifica avrebbe dovuto propagarsi ad altre aree del codice. In questo senso, l'uso diretto della proprietà è più fragile dell'uso dell'interfaccia fornita dalla classe.


15
Ohhh, perché self.age potrebbe riferirsi a una variabile di istanza oa un metodo di istanza?
Nolan Amy,

@. @ ... triste questo è il caso
cyc115

7

Stai attento quando erediti una classe da Struct.newcui è un modo chiaro per generare un inizializzatore ( Come generare un inizializzatore in Ruby? )

class Node < Struct.new(:value)
    def initialize(value)
        @value = value
    end
    def show()
        p @value
        p self.value # or `p value`
    end
end 

n = Node.new(30)
n.show()

sarà di ritorno

30
nil

Tuttavia, quando si rimuove l'inizializzatore, verrà restituito

nil
30

Con la definizione della classe

class Node2
    attr_accessor :value
    def initialize(value)
        @value = value
    end
    def show()
        p @value
        p self.value
    end
end

Dovresti fornire il costruttore.

n2 = Node2.new(30)
n2.show()

sarà di ritorno

30
30

Grazie per l'esempio @Prosseek, attualmente sto imparando Ruby on Rails e questo è esattamente il tipo di comportamento che mi fa sentire che Ruby è inutilmente complicato>. <.
cyc115,

3

La prima risposta è del tutto corretta, ma come newbie relativo non mi è stato subito chiaro cosa implicasse (inviare messaggi a se stessi? Uh eh ...). Penso che un breve esempio aiuterà:

class CrazyAccessors
  def bar=(val)
    @bar = val - 20 # sets @bar to (input - 20)
  end
  def bar
    @bar
  end

  def baz=(value)
    self.bar = value # goes through `bar=` method, so @bar = (50 - 20)
  end

  def quux=(value)
    @bar = value     # sets @bar directly to 50
  end
end

obj  = CrazyAccessors.new
obj.baz = 50
obj.bar  # => 30
obj.quux = 50
obj.bar  # => 50

8
Questo esempio ha reso le cose più confuse.
Oskar Holmkratz,

1
Mi dispiace ma l'esempio non è abbastanza commentato per me. Non posso seguire il tuo ragionamento.
Kouty,

Qualcuno che proviene da Smalltalk dirà che un oggetto "invia un messaggio a se stesso". Qualcuno che viene da Python dirà che un oggetto "chiama un metodo su se stesso". Non essere confuso; sono esattamente la stessa cosa. (Un purista di semantica può obiettare che sono gli stessi solo per i linguaggi con tipizzazione dinamica e che una chiamata al metodo virtuale C ++ non è esattamente la stessa di quella di inviare un messaggio. Il purista è corretto, ma probabilmente non rientra nell'ambito di questa domanda / risposta.)
GrandOpener

Mi piace l'esempio, ma ti preghiamo di fornire qualche commento in più su ciò che sta realmente accadendo. Difficile da seguire senza spiegazioni
CalamityAdam,

2

Non c'è alcuna differenza. Sospetto che sia stato fatto apposta per il valore documentario di vedere self.agee other_person.ageavvicinarsi.

Suppongo che l'uso consenta di scrivere in futuro un vero getter, il che potrebbe fare qualcosa di più complesso che restituire semplicemente una variabile di istanza, e in tal caso il metodo non dovrebbe cambiare.

Ma è un'astrazione improbabile di cui preoccuparsi, dopo tutto, se l'implementazione dell'oggetto è cambiata è ragionevole cambiare altri metodi, ad un certo punto un semplice riferimento all'interno dell'oggetto stesso è perfettamente ragionevole.

In ogni caso, l'astrazione della ageproprietà non spiega ancora l'uso esplicito di self, in quanto semplicemente ageavrebbe invocato l'accessor.


-3

@age - è sicuramente l'età variabile dell'istanza

self.age: si riferisce all'età della proprietà dell'istanza.

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.