2009-11-07 13 views
162

Hier ist ein Code:Instanz variable: self vs @

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 

Was will ich wissen, ist der Unterschied zwischen @age und self.age in age_difference_with Verfahren.

Antwort

237

Schreiben @age greift direkt auf die Instanzvariable @age zu. Das Schreiben sagt dem Objekt, dass es die Nachricht age senden soll, die normalerweise die Instanzvariable @age zurückgibt - aber könnte eine Reihe anderer Dinge tun, abhängig davon, wie die age-Methode in einer bestimmten Unterklasse implementiert wird. Zum Beispiel könnten Sie eine MiddleAgedSocialite-Klasse haben, die ihr Alter immer um 10 Jahre jünger angibt, als es tatsächlich ist. Oder praktischer gesagt, könnte eine PersistentPerson-Klasse die Daten aus einem persistenten Speicher lazy lesen, alle persistenten Daten in einem Hash zwischenspeichern.

+1

Ich habe einmal ein Buch in Schienen gelesen und verstehe nicht den Unterschied zwischen diesem Selbst und @, also sollte ich immer self.var_name in meinen Methoden verwenden (das nicht Setter und Getter), um meine Daten mit öffentlichen Schnittstelle zu machen, Ich habe Zeit damit verbracht, es in Getter und Setter zu definieren, oder? – sarunw

+0

... Englisch ... was meinst du mit einer Anzahl von Dingen. Ich habe die letzten beiden Beispiele nicht bekommen. – user2167582

21

Der Unterschied ist, dass es die Verwendung der Methode von der Implementierung isoliert. Wenn sich die Implementierung der Eigenschaft ändern würde - beispielsweise das Geburtsdatum beibehalten und dann das Alter auf der Grundlage des Zeitunterschieds zwischen jetzt und dem Geburtsdatum berechnen - dann muss sich der von der Methode abhängige Code nicht ändern. Wenn die Eigenschaft direkt verwendet wird, muss die Änderung auf andere Bereiche des Codes übertragen werden. In diesem Sinne ist die direkte Verwendung der Eigenschaft fragiler als die Verwendung der von der Klasse bereitgestellten Schnittstelle.

+12

Ohhh, weil sich self.age auf eine Instanzvariable oder eine Instanzmethode beziehen könnte? –

2

Es gibt keinen Unterschied. Ich vermute, dass es nur für den dokumentarischen Wert gemacht wurde, und other_person.age nebeneinander zu sehen.

Ich nehme an, dass die Verwendung ermöglicht, dass ein tatsächlicher Getter in der Zukunft geschrieben wird, der etwas Komplexeres tun könnte, als nur eine Instanzvariable zurückzugeben, und in diesem Fall müsste die Methode nicht geändert werden.

Aber das ist eine unwahrscheinliche Abstraktion zu kümmern, schließlich, wenn die Implementierung des Objekts geändert hat, ist es sinnvoll, andere Methoden zu ändern, irgendwann ist eine einfache Referenz innerhalb des Objekts selbst völlig in Ordnung.

In jedem Fall, Abstraktion der age -Eigenschaft noch nicht die explizite Verwendung von self zu erklären, wie nur age würde auch den Accessor aufgerufen haben.

5

gewarnt werden, wenn Sie eine Klasse von Struct.new erben, die eine nette Art und Weise ist eine intializer (How to generate initializer 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() 

wird

Rückkehr
30 
nil 

jedoch zu generieren, wenn Sie die initializer entfernen, wird zurückgegeben

nil 
30 

Mit der Klassendefinition

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

Sie sollten den Konstruktor bereitstellen.

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

kehrt

30 
30 
-3

@age - ist auf jeden Fall die Instanzvariable Alter

self.age - bezieht sich auf die Instanz Eigenschaft Alter.

-1

Die erste Antwort ist völlig korrekt, aber als ein relativer Neuling war es mir nicht sofort klar, was es bedeutete (Senden von Nachrichten an sich selbst? Uh huh ...). Ich denke, dass ein kurzes Beispiel helfen wird:

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 
+2

Dieses Beispiel machte die Dinge verwirrender. –

+0

Es tut mir leid, aber das Beispiel ist nicht genug für mich kommentiert. Ich kann deiner Argumentation nicht folgen. – kouty