Ruby: метод необъяснимо перезаписан и установлен на ноль - PullRequest
7 голосов
/ 14 декабря 2011

Если я выполню этот код рубина:

def foo
  100
end

p defined?(foo), foo
if false
  foo = 200
end
p defined?(foo), foo

Вывод, который я получаю:

"method"
100
"local-variable"
nil

Может ли кто-нибудь объяснить мне, почему foo установлен на nil после не выполнения if? Это ожидаемое поведение или ошибка в рубине?

Ответы [ 2 ]

5 голосов
/ 14 декабря 2011

Имена в левой части назначений устанавливаются на nil, даже если код не может быть достигнут, как в случае if false.

>> foo
NameError: undefined local variable or method `foo' for main:Object
...
>> if false
..   foo = 1
..   end #=> nil
>> foo #=> nil

Когда Ruby пытается разрешить голые слова, он сначала ищет локальные переменные (есть ссылка на это в книге «Кирка», которую я сейчас не могу найти). Так как теперь у вас есть один с именем foo, он отображает nil. Как отметил Миша, этот метод все еще можно назвать foo().

1 голос
/ 26 ноября 2013

Вот что сказал мой приятель и супер-эксперт по Ruby Джош Чик:

Когда Ruby видит назначение, он инициализирует переменную в текущей области и устанавливает ее равной nil. Поскольку назначение не было выполнено, оно не обновило значение foo.

если операторы не изменяют область видимости, как блоки. Это также самое важное различие между

for x in xs

и

xs.each { |x| }

Вот еще один пример:

a = 123 if a  # => nil
a  # => nil

Мы не должны быть в состоянии сказать if a, потому что мы никогда не устанавливаем a, но Руби видит a = 123 и инициализирует a, а затем достигает if a, в этот момент a равен nil

Я бы на самом деле посчитал это прихотью переводчика. Гари Бернхардт высмеивает это в вате (https://www.destroyallsoftware.com/talks/wat) с a = a

-Josh

...