2009-11-07 12 views
162

Oto kod:Instance zmienna: 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 

Co chcę wiedzieć, jest różnica między używaniem @age i self.age w age_difference_with metody.

Odpowiedz

237

Zapisywanie @age zapewnia bezpośredni dostęp do zmiennej instancji @age. Zapisanie self.age mówi obiektowi, aby wysłał sobie wiadomość age, która zwykle zwróci zmienną instancji @age - ale może wykonać dowolną liczbę innych rzeczy w zależności od sposobu implementacji metody age w danej podklasie. Na przykład możesz mieć klasę MiddleAgedSocialite, która zawsze zgłasza swój wiek o 10 lat młodziej niż jest w rzeczywistości. Praktycznie, klasa PersistentPerson może leniwie odczytać te dane z magazynu trwałego, buforować wszystkie swoje trwałe dane w haszyszu.

+1

Kiedyś czytałem książkę w szynach i nie rozumiem różnicy między tym self a @, więc zawsze powinieneś używać self.var_name w moich metodach (to nie setter i getter), aby moje dane były używane za pomocą publicznego interfejsu, Spędziłem czas definiując go w getter i seter, prawda? – sarunw

+0

... angielski ... co masz na myśli przez dowolną liczbę rzeczy. nie dostałem tych dwóch ostatnich przykładów. – user2167582

21

Różnica polega na tym, że izoluje wykorzystanie metody od jej wdrożenia. Jeśli implementacja własności ulegnie zmianie - powiedzmy, aby zachować datę urodzin, a następnie obliczyć wiek w oparciu o różnicę w czasie od teraz do daty urodzenia - wtedy kod w zależności od metody nie musi się zmieniać. Jeśli bezpośrednio użyje tej właściwości, zmiana będzie musiała zostać przeniesiona na inne obszary kodu. W tym sensie korzystanie z właściwości bezpośrednio jest bardziej kruche niż użycie interfejsu dostarczonego przez klasę.

+12

Ohhh, ponieważ self.age może odnosić się do zmiennej instancji lub metody instancji? –

2

Nie ma żadnej różnicy. Podejrzewam, że zrobiono to tylko dla wartości dokumentalnej oglądania w pobliżu siebie nawzajem self.age i other_person.age.

Przypuszczam, że użycie pozwala na zapisywanie faktycznego gettera w przyszłości, co może zrobić coś bardziej skomplikowanego niż tylko zwrócenie zmiennej instancji, w takim przypadku metoda nie musiałaby się zmieniać.

Ale jest to mało prawdopodobne, aby się martwić abstrakcją, w końcu, jeśli zmiana obiektu jest uzasadniona, aby zmienić inne metody, w pewnym momencie proste odniesienie w samym obiekcie jest całkowicie uzasadnione.

W każdym razie, abstrakcja nieruchomości age nadal nie wyjaśnia wyraźne użycie self, jak po prostu age również powołały się na akcesor.

5

Uważajcie jeśli dziedziczą klasa od Struct.new który jest schludny sposób, aby wygenerować 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() 

powróci

30 
nil 

Jednak po wyjęciu inicjator, to zwróci

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ć konstruktora.

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

powróci

30 
30 
-3

@age - to z pewnością przypadek zmiennej wiek

self.age - odnosi się do wieku przykład właściwości.

-1

Pierwsza odpowiedź jest całkowicie poprawna, ale jako względny początkujący nie było dla mnie jasne, co to oznacza (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 
+2

Ten przykład sprawił, że sprawy stały się bardziej mylące. –

+0

Przykro mi, ale ten przykład nie jest dla mnie wystarczająco komentowany. Nie mogę podążać za twoim rozumowaniem. – kouty