Odpowiedzi:
Pisanie @age
bezpośrednio uzyskuje dostęp do zmiennej instancji @age
. Pisanie self.age
mówi obiektowi, aby sam wysłał wiadomość age
, która zwykle zwróci zmienną instancji @age
- ale może zrobić dowolną liczbę innych rzeczy w zależności od age
sposobu implementacji metody w danej podklasie. Na przykład możesz mieć klasę MiddleAgedSocialite, która zawsze podaje wiek o 10 lat młodszy niż w rzeczywistości. Lub, bardziej praktycznie, klasa PersistentPerson może leniwie odczytać te dane z trwałego sklepu, buforować wszystkie swoje trwałe dane w haszu.
Różnica polega na tym, że izoluje użycie metody od jej wdrożenia. Jeśli implementacja właściwości miałaby ulec zmianie - powiedzmy, aby zachować datę urodzenia, a następnie obliczyć wiek na podstawie różnicy czasu między teraz a datą urodzenia - kod w zależności od metody nie musi się zmieniać. Jeśli użyłby tej właściwości bezpośrednio, zmiana musiałaby się rozprzestrzenić na inne obszary kodu. W tym sensie bezpośrednie użycie właściwości jest bardziej kruche niż użycie interfejsu zapewnianego przez klasę.
Ostrzegaj, gdy odziedziczysz klasę, z Struct.new
której jest dobry sposób na wygenerowanie intializatora ( Jak wygenerować inicjalizator w 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()
wróci
30
nil
Jednak po usunięciu inicjalizatora zostanie on zwrócony
nil
30
Z definicją klasy
class Node2
attr_accessor :value
def initialize(value)
@value = value
end
def show()
p @value
p self.value
end
end
Powinieneś podać konstruktor.
n2 = Node2.new(30)
n2.show()
wróci
30
30
Pierwsza odpowiedź jest całkowicie poprawna, ale jako względny początkujący nie od razu zrozumiałem, co to sugeruje (wysyłanie wiadomości do siebie? Huh ...). Myślę, że krótki przykład pomoże:
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
Nie ma żadnej różnicy. Podejrzewam, że zrobiono to tylko dla dokumentalnej wartości widzenia self.age
i other_person.age
zbliżania się do siebie.
Podejrzewam, że użycie pozwala na napisanie w przyszłości faktycznego gettera, co może zrobić coś bardziej złożonego niż tylko zwrócenie zmiennej instancji, a w takim przypadku metoda nie musiałaby się zmieniać.
Jest to jednak mało prawdopodobna abstrakcja, o którą należy się martwić, jeśli zmiana implementacji obiektu jest uzasadniona, należy zmienić inne metody, w pewnym momencie proste odniesienie do samego obiektu jest całkowicie uzasadnione.
W każdym razie abstrakcja age
własności wciąż nie wyjaśnia jednoznacznego użycia self
, ponieważ zwykły age
przywołałby również akcesora.
@ wiek - to zdecydowanie wiek zmiennej instancji
self.age - odnosi się do wieku własności instancji.