Переменная экземпляра: 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
То, что я хочу знать, - это разница между использованием методов @age
и self.age
в age_difference_with
.
Ответы
Ответ 1
Запись @age
позволяет получить доступ к переменной экземпляра @age
. Написание self.age
указывает объекту отправить сообщение age
, которое обычно возвращает переменную экземпляра @age
, но может делать любое количество других вещей в зависимости от того, как метод age
реализован в данном подклассе. Например, у вас может быть класс MiddleAgedSocialite, который всегда сообщает о возрасте на 10 лет моложе, чем он есть на самом деле. Более того, класс PersistentPerson может лениво читать эти данные из постоянного хранилища, кэшировать все свои постоянные данные в хеше.
Ответ 2
Разница заключается в том, что она изолирует использование метода от его реализации. Если бы реализация свойства должна была измениться - скажем, чтобы сохранить дату рождения, а затем рассчитать возраст, основанный на разнице во времени между теперь и датой рождения, - тогда код, зависящий от метода, не нуждается в изменении. Если он использовал свойство напрямую, это изменение должно распространяться на другие области кода. В этом смысле использование свойства напрямую более хрупко, чем использование интерфейса, предоставляемого классом.
Ответ 3
Предупредить, когда вы наследуете класс от Struct.new
, который является аккуратным способом генерации intializer (Как генерировать инициализатор в 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()
вернет
30
nil
Однако при удалении инициализатора он вернет
nil
30
С определением класса
class Node2
attr_accessor :value
def initialize(value)
@value = value
end
def show()
p @value
p self.value
end
end
Вы должны предоставить конструктор.
n2 = Node2.new(30)
n2.show()
вернет
30
30
Ответ 4
Нет никакой разницы. Я подозреваю, что это было сделано только для документального значения просмотра self.age
и other_person.age
рядом друг с другом.
Я полагаю, что использование позволяет в будущем записывать фактический геттер, что может сделать что-то более сложное, чем просто вернуть переменную экземпляра, и в этом случае метод не нужно будет изменять.
Но маловероятно, чтобы абстракция беспокоилась о том, что если реализация объекта изменилась, разумно изменить другие методы, в какой-то момент простая ссылка внутри самого объекта вполне разумна.
В любом случае абстракция свойства age
по-прежнему не объясняет явное использование self
, так как просто обычный age
также вызвал бы аксессор.
Ответ 5
Первый ответ полностью правильный, но, как относительный новичок, мне не сразу стало ясно, что он подразумевал (отправляя сообщения самому себе... хм...). Я думаю, что короткий пример поможет:
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
Ответ 6
вызов self.value для получателя. Потому что, когда вы вызываете self.value в классе.
Ошибка: неопределенный метод 'value'. Я должен объявить геттер для класса
Ответ 7
@age - определенно возраст переменной экземпляра
self.age - относится к возрасту свойства экземпляра.