Variable d’instance: self vs @

Voici un code:

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 

Ce que je veux savoir, c’est la différence entre l’utilisation de @age et self.age dans la méthode age_difference_with .

L’écriture de @age accède directement à la variable d’instance @age . L’écriture de self.age indique à l’object d’envoyer lui-même l’ age du message, qui retournera généralement la variable d’instance @age – mais pourrait faire un certain nombre d’autres choses en fonction de la manière dont la méthode age est implémentée dans une sous-classe donnée. Par exemple, vous pourriez avoir une classe MiddleAgedSocialite qui affiche toujours son âge de 10 ans de moins qu’elle ne l’est réellement. Ou plus concrètement, une classe PersistentPerson peut lire paresseusement ces données depuis un magasin persistant, mettre en cache toutes ses données persistantes dans un hachage.

La différence est qu’elle isole l’utilisation de la méthode de sa mise en œuvre. Si la mise en œuvre de la propriété devait changer, par exemple pour conserver la date de naissance et calculer l’âge en fonction de la différence de temps entre la date de naissance et la date de naissance, le code ne dépend pas de la méthode. S’il utilisait directement la propriété, la modification devrait se propager aux autres zones du code. En ce sens, l’utilisation directe de la propriété est plus fragile que l’utilisation de l’interface fournie par la classe.

Soyez averti lorsque vous Struct.new une classe de Struct.new qui est un bon moyen de générer un intializer ( Comment générer l’initialiseur dans 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() 

reviendra

 30 nil 

Cependant, lorsque vous supprimez l'initialiseur, il retournera

 nil 30 

Avec la définition de classe

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

Vous devez fournir le constructeur.

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

reviendra

 30 30 

Il n’y a pas de différence. Je soupçonne que cela a été fait juste pour la valeur documentaire de voir self.age et other_person.age près l’un de l’autre.

Je suppose que l’utilisation permet à un getter réel d’être écrit dans le futur, ce qui pourrait faire quelque chose de plus complexe que de renvoyer simplement une variable d’instance, et dans ce cas la méthode n’aurait pas besoin de changer.

Mais c’est une abstraction improbable à laquelle il faut s’inquiéter, après tout, si l’implémentation de l’object est modifiée, il est raisonnable de changer d’autres méthodes, à un moment donné, une simple référence dans l’object est parfaitement raisonnable.

Dans tous les cas, l’abstraction de la propriété age n’explique toujours pas l’utilisation explicite de self , car le simple age aurait également invoqué l’accesseur.

La première réponse est tout à fait correcte, mais en tant que relative novice, je n’ai pas immédiatement compris ce que cela impliquait (envoyer des messages à moi-même? Euh …). Je pense qu’un petit exemple aidera:

 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 

@age – est certainement l’âge variable de l’instance

self.age – fait référence à l’âge de la propriété de l’instance.