Ответ 1
В Ruby большинство неинициализированных или даже несуществующих переменных оцениваются до nil
. Это верно для локальных переменных, переменных экземпляра и глобальных переменных:
defined? foo #=> nil
local_variables #=> []
if false
foo = 42
end
defined? foo #=> 'local-variable'
local_variables #=> [:foo]
foo #=> nil
foo.nil? #=> true
defined? @bar #=> nil
instance_variables #=> []
@bar #=> nil
@bar.nil? #=> true
# warning: instance variable @bar not initialized
defined? $baz #=> nil
$baz #=> nil
# warning: global variable `$baz' not initialized
$baz.nil? #=> true
# warning: global variable `$baz' not initialized
Это, однако, неверно для переменных и констант иерархии классов:
defined? @@wah #=> nil
@@wah
# NameError: uninitialized class variable @@wah in Object
defined? QUUX #=> nil
QUUX
# NameError: uninitialized constant Object::QUUX
Это красная селедка:
defined? fnord #=> nil
local_variables #=> []
fnord
# NameError: undefined local variable or method `fnord' for main:Object
Причина, по которой вы получаете сообщение об ошибке, заключается не в том, что унифицированные локальные переменные не оцениваются до nil
, это значит, что fnord
неоднозначно: это может быть либо сообщение без аргументов, отправляемое получателю по умолчанию ( т.е. эквивалентно self.fnord()
) или доступ к локальной переменной fnord
.
Чтобы устранить эту проблему, вам нужно добавить ресивер или список аргументов (даже если пустой), чтобы сообщить Ruby, что это сообщение отправлено:
self.fnord
# NoMethodError: undefined method `fnord' for main:Object
fnord()
# NoMethodError: undefined method `fnord' for main:Object
или убедитесь, что анализатор (а не оценщик) анализирует (не выполняет) назначение перед использованием, сообщает Ruby, что это локальная переменная:
if false
fnord = 42
end
fnord #=> nil
почему переменная экземпляра обрабатывается иначе, чем локальная и переменная класса?
Это не так. Он обрабатывал то же, что и локальная переменная. Переменная иерархии классов - это та, которая ведет себя по-разному, локальные переменные, переменные экземпляра и глобальные переменные ведут себя одинаково.
есть другие причины & hellip; не могут ли переменные класса так себя вести?
Я не знаю. Например, переменные очень удобны, поскольку, например, в отличие от Java, где переменные экземпляра объявляются в определении класса и поэтому всегда существуют для каждого экземпляра класса, в Ruby переменные экземпляра нигде не объявляются. Они просто магически spring в существование, как только они назначены. Поскольку переменные экземпляра не обязательно гарантированно существуют, писать методы, которые используют переменные экземпляра, были бы болью, если бы они бросали исключения.
Почему переменные иерархии классов разные, я понятия не имею. Может быть, потому, что никто их не использует, или потому, что обычно они обычно инициализируются в классе и просто не доступны, когда они не инициализируются.