Итак, мы имеем код:Рубины "определены?" оператор работает неправильно?
class Foo
def bar
puts "Before existent: #{(defined? some_variable)}"
puts "Before not_existent: #{(defined? nonexistent_variable)}"
raise "error"
some_variable = 42
rescue
puts "exception"
ensure
puts "Ensure existent: #{(defined? some_variable)}"
puts "Ensure not_existent: #{(defined? nonexistent_variable)}"
end
end
И вызвать его из IRB:
> Foo.new.bar
И, что вернется:
Before existent:
Before not_existent:
exception
Ensure existent: local-variable
Ensure not_existent:
=> nil
А теперь вопрос - почему? Мы собрали исключение до, чем some_variable
. Почему это работает так? Почему some_variable
определен в блоке обеспечения? (Кстати, она определяется как ноль)
UPDATE: Спасибо @Max для ответа, но если мы изменим код, чтобы использовать переменную экземпляра:
class Foo
def bar
puts "Before existent: #{(defined? @some_variable)}"
puts "Before not_existent: #{(defined? @nonexistent_variable)}"
raise "error"
@some_variable = 42
ensure
puts "Ensure existent: #{(defined? @some_variable)}"
puts "Ensure not_existent: #{(defined? @nonexistent_variable)}"
end
end
Он работает, как ожидалось:
Before existent:
Before not_existent:
Ensure existent:
Ensure not_existent:
Почему?
Ссылки на неопределенные переменные экземпляра (и глобальные) обрабатываются по-разному, чем ссылки на неопределенные локальные (и классные) переменные. Например, 'puts @a # => nil', тогда как' помещает #NameError: неопределенную локальную переменную или метод 'a 'для main: Object'. –