2015-08-23 4 views

ответ

2

Попробуйте это:

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" 
+0

Ваш последний абзац, кажется, пропустит точку. Обратите внимание, что код имеет 'attr_reader: bar'. Проблема не в конфликте между 'bar' и' @ bar'; он находится между локальной переменной 'bar' и методом' bar'. – sawa

+0

@sawa, черт, я пропустил аксессуар в полном объеме. Спасибо, что дали мне знать. Исправлено, я думаю. –

+0

Я изменил 'attr_reader' на' attr_accessor' и запустил ваш код. Он по-прежнему дает точно такой же результат ('bar' -' nil', а не '123'). – Anand

1

До тех пор, как линия

bar = "123" 

разбирается, он инициализирует локальную переменную bar к nil в пределах объема, даже если он не выполняется. Это поведение (характеристика локальных переменных) связано с локальными переменными, использующими лексическую область; их область действия должна определяться без выполнения кода. И когда токен неоднозначен между локальной переменной и методом, она интерпретируется как локальная переменная.

1

p bar не вернется "abc" потому bar и @bar различны. @bar - это переменная экземпляра, но когда вы вызываете ее без префикса @, ruby ​​ищет локальную переменную.

Обычно в ruby ​​переменные экземпляра и глобальные переменные, если они не определены, возвращают nil. Но локальные переменные бросают ошибку, когда не определено. Но в вашем случае вы пытались инициализировать переменную, даже если она никогда не инициализируется из-за if false, она все еще анализируется, и этого достаточно, чтобы интерпретатор ruby ​​возвращал nil.

Это было четко объяснено в this link

 Смежные вопросы

  • Нет связанных вопросов^_^