Voici du 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 age_difference_with
méthode.
L'écriture @age
accède directement à la variable d'instance @age
. L'écriture self.age
indique à l'objet de s'envoyer le message age
, qui retournera généralement la variable d'instance @age
- mais pourrait faire un certain nombre d'autres choses selon la façon dont la méthode age
est implémentée dans une sous-classe donnée. Par exemple, vous pourriez avoir une classe MiddleAgedSocialite qui rapporte toujours son âge 10 ans de moins qu'il ne l'est réellement. Ou plus concrètement, une classe PersistentPerson pourrait lire paresseusement ces données à partir d'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 - disons pour garder la date de naissance puis calculer l'âge en fonction de la différence de temps entre maintenant et la date de naissance - alors le code selon la méthode n'a pas besoin de changer. S'il utilisait directement la propriété, la modification devrait se propager à d'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 héritez d'une classe de Struct.new
qui est un bon moyen de générer un initialiseur ( Comment générer un 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 reviendra
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 aucune différence. Je soupçonne que cela a été fait juste pour la valeur documentaire de voir self.age
et other_person.age
les uns à côté des autres.
Je suppose que l'utilisation permet à un getter réel d'être écrit à l'avenir, ce qui pourrait faire quelque chose de plus complexe que de simplement renvoyer une variable d'instance, et dans ce cas, la méthode n'aurait pas besoin de changer.
Mais c'est une abstraction improbable à craindre, après tout, si la mise en œuvre de l'objet a changé, il est raisonnable de changer d'autres méthodes, à un moment donné, une simple référence dans l'objet lui-même est parfaitement raisonnable.
Dans tous les cas, l'abstraction de la propriété age
n'explique toujours pas l'utilisation explicite de self
, car simplement age
aurait également appelé l'accesseur.
La première réponse est entièrement correcte, mais en tant que débutant relatif, je n'ai pas immédiatement compris ce que cela impliquait (envoyer des messages à soi-même? Euh huh ...). Je pense qu'un court 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