Попробуйте это:
class Foo
attr_reader :bar
def initialize
p "instance methods defined in Foo: #{self.methods(false)}"
@bar = "abc"
p "defined? @bar: #{defined? @bar}"
p "bar: #{bar}"
p "defined? bar: #{defined? bar}"
if false
bar = "123"
end
p "defined? bar, 2nd time: #{defined? bar}"
p "bar.nil? = #{bar.nil?}"
p "self.bar = #{self.bar}"
p "instance methods defined in Foo: #{self.class.instance_methods(false)}"
end
end
Foo.new
"instance methods defined in Foo: [:bar]"
"defined? @bar: instance-variable"
"bar: abc"
"defined? bar: method"
"defined? bar, 2nd time: local-variable"
"bar.nil? = true"
"self.bar = abc"
"instance methods defined in Foo: [:bar]"
Линия:
"defined? @bar: instance-variable"
"defined? bar: method"
показывает, что @bar
является переменным экземпляром и bar
является методом экземпляра, а именно метод геттера для @bar
созданного attr_reader :bar
. Перед
if false
bar = "123"
end
оценивается, Ruby всматривается в статье if
. Там она видит bar = "123"
. Если вызывается, это присваивает значение "123"
неинициализированной локальной переменной bar
.
bar=
не может быть методом экземпляра (например, примером для @bar
), потому что любой метод, название которого заканчивается знак равенства должен быть вызван на явного приемника. (Он работает таким образом, чтобы кодеры могли использовать локальные переменные, которые имеют те же имена, что и переменные экземпляра, минус ведущие @
.)
Что такое «явный» приемник? Если Foo
был публичный метод экземпляра buz
, вы могли бы написать:
foo = Foo.new
foo.buz
foo
является явным приемником для метода buz
. Чтобы вызвать buz
изнутри одного из методов экземпляра Foo
«s, вы могли бы использовать явный приемник:
self.buz
или просто написать:
buz
в этом случае self
является неявного приемника.
Как bar=
можно записать только с явным приемником, мы должны были бы писать:
attr_writer :bar
...
self.bar = "123"
для вызова сеттера @bar
«s.
Где мы находимся? Ах, мы просто пришли к выводу, что:
if false
bar = "123"
end
бы присвоить значение локальной переменной bar
если предложение if
были выполнены, независимо от того, существует ли способ Foo#bar=
.
Поскольку false
, ну, false
, содержание пункта if
не выполняются, так что значение bar
не изменяется от nil
.
Важно то, что локальная переменная bar
и экземпляр переменной @bar
так же отличаются друг от друга, как это night
и @day
. Мы можем легко показать, что следующим образом:
a = 'cat'
@a = 'dog'
a #=> "cat"
a = 'pig'
@a #=> "dog"
, потому что 'bar' не то же самое, как' @ bar'. –