После создания первой переменной экземпляра что-нибудь с помощью метода instnace_variable_set
я понимаю, что я создаю attr_reader, верно?
Нет, это не правильно.Ваш класс никогда не создает (или не запускает) attr_reader
.Попробуйте это (после запуска ваших примеров команд)
p( uber_hash.methods - Object.new.methods )
, и вы увидите, что только методы, дополнительно определенные в вашем классе, будут [:color, :color=, :method_missing]
в вашем классе.
Метод :color
определениз-за attr_accessor :color
.Помните, attr_accessor
и т. Д. - это просто ярлык для определения методов.В отличие от этого, метод :anything
не определен , поскольку ваш класс никогда не определял этот метод.Вместо этого в вашем классе каждый раз, когда вызывается метод uber_hash.anything
, uber_hash.method_missing
запускается и выполняет работу, то есть манипулирует или просматривает переменную экземпляра @anything
.
Во-вторых, в то время как instance_variable_set
устанавливает значение переменной экземпляра (и создает его, если оно не существует), instance_variable_get
ссылается на него, только если оно существует, в противном случае возвращает nil и не создает переменную экземпляра.Вот почему @anything
создается после instance_variable_set
, а не только после instance_variable_get
.Попробуйте это, чтобы понять смысл (после того, как вы определили класс).
class UberHash
def test_pr
print 'color='; p instance_variable_get("@color")
print 'other='; p instance_variable_get("@other")
p instance_variables # => @other is not defined
print 'other='; p instance_variable_set("@other", 99)
p instance_variables # => @other is NOW defined
end
end
uber_hash.test_pr
Следовательно, поведение, которое вы видите, совершенно законно.
Примечание: этот последний ответ объясняет это.