Zmienna instancji: self vs @

Oto jakiś kod:

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

Chcę wiedzieć, jaka jest różnica między użyciem @age i self.age w metodzie age_difference_with.

Author: evuez, 2009-11-07

6 answers

Zapis @age bezpośrednio uzyskuje dostęp do zmiennej instancji @age. Writing self.age mówi obiektowi, aby sam wysłał wiadomość age, która zazwyczaj zwraca zmienną instancji @age - ale może wykonać wiele innych czynności w zależności od tego, jak Metoda age jest zaimplementowana w danej podklasie. Na przykład możesz mieć klasę MiddleAgedSocialite, która zawsze zgłasza swój wiek o 10 lat młodszy niż w rzeczywistości. Lub bardziej praktycznie, Klasa PersistentPerson może leniwie odczytać te dane ze sklepu trwałego buforuj wszystkie jego trwałe DANE w hash.

 247
Author: Chuck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-07 15:08:24

Różnica polega na tym, że izoluje zastosowanie metody od jej implementacji. Jeśli implementacja właściwości miała się zmienić-powiedzmy, aby zachować datę urodzenia, a następnie obliczyć wiek na podstawie różnicy w czasie między datą teraz a datą urodzenia-wtedy kod w zależności od metody nie musi się zmieniać. Jeśli użyje tej właściwości bezpośrednio, to zmiana musiałaby rozprzestrzeniać się na inne obszary kodu. W tym sensie korzystanie z nieruchomości bezpośrednio jest bardziej kruche niż za pomocą dostarczonego mu interfejsu klasy.

 23
Author: tvanfosson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-07 14:41:52

Bądź ostrzeżony, gdy dziedziczysz klasę z Struct.newco jest dobrym sposobem na wygenerowanie intializera ( Jak wygenerować initializer w Rubim?)

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 usunięciu inicjalizatora 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ć konstruktor.

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

Powróci

30
30
 5
Author: prosseek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:10:33

Nie ma żadnej różnicy. Podejrzewam, że zrobiono to tylko dla dokumentalnej wartości widzenia self.age i other_person.age blisko siebie.

Przypuszczam, że użycie pozwala na zapisanie rzeczywistego gettera w przyszłości, 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ć.

Ale to mało prawdopodobna abstrakcja, o którą należy się martwić, w końcu, jeśli implementacja obiektu uległa zmianie, rozsądne jest, aby zmień inne metody, w pewnym momencie proste odniesienie w samym obiekcie jest całkowicie rozsądne.

W każdym razie, abstrakcja właściwości age nadal nie wyjaśnia jawnego użycia self, ponieważ zwykły age również wywołałby accessor.

 2
Author: DigitalRoss,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-07 14:53:29

Pierwsza odpowiedź jest całkowicie poprawna, ale jako względny nowicjusz nie od razu zrozumiałam, co to oznacza (wysyłanie wiadomości do siebie? uh 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
 -1
Author: blob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-04 13:52:17

@ age - to na pewno zmienna wieku instancji

Self.age-odnosi się do właściwości instance age.

 -3
Author: LEM Adane,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-06 01:26:24