В Ruby, почему после запуска irb, foo.nil? говорит неопределенную ошибку, а @ foo.nil? дает "правда", а @@ wah.nil? снова выдает ошибку? - PullRequest
13 голосов
/ 26 октября 2010

То же в Ruby 1.8.7 и 1.9.2:

$ irb

ruby-1.8.7-p302 > foo.nil?
NameError: undefined local variable or method `foo' for #<Object:0x3794c>
    from (irb):1

ruby-1.8.7-p302 > @bar.nil?
 => true 

ruby-1.8.7-p302 > @@wah.nil?
NameError: uninitialized class variable @@wah in Object
    from (irb):3

почему переменная экземпляра обрабатывается иначе, чем локальная переменная и переменная класса?

1 Ответ

17 голосов
/ 26 октября 2010

В 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.

InЧтобы устранить неоднозначность, вам нужно добавить получатель или список аргументов (даже если он пуст), чтобы сообщить Ruby, что это сообщение отправлено:

self.fnord
# NoMethodError: undefined method `fnord' for main:Object
fnord()
# NoMethodError: undefined method `fnord' for main:Object

или убедиться, что parser ( not оценщик) анализирует ( not выполняет) присвоение перед использованием, чтобы сообщить Ruby, что это локальная переменная:

if false
  fnord = 42
end
fnord              #=> nil

почему переменная экземпляра обрабатывается иначе, чем локальная переменная и переменная класса?

На самом деле это не так.Он обрабатывается так же, как локальная переменная.Переменная иерархии классов - это та, которая ведет себя по-разному, локальные переменные, переменные экземпляра и глобальные переменные ведут себя одинаково.

есть ли другие причины ... переменные класса не могут вести себя так же?

Я не знаю.Для переменных экземпляра это очень удобно, поскольку в отличие от Java, например, где переменные экземпляра объявляются в определении класса и, таким образом, всегда существуют для каждого экземпляра класса, в Ruby переменные экземпляра нигде не объявляются.Они просто волшебным образом возникают, как только их назначают.Поскольку переменные экземпляров не обязательно гарантированы для существования, написание методов, использующих переменные экземпляров, было бы проблематично, если бы они вызывали исключения.

Почему переменные иерархии классов отличаются, я понятия не имею.Может быть, это потому, что никто не использует их в любом случае, или потому что они обычно имеют тенденцию инициализироваться в теле класса и просто не доступны, когда они не инициализированы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...