Я не понимаю рубиново локальную сферу - PullRequest
49 голосов
/ 11 ноября 2010

В этом примере

def foo(x)
  if(x > 5)
    bar = 100
  end
  puts bar
end

Затем foo (6) Вывод: 100 и foo (3) ничего не выводят.

Однако, если я изменил определение на

def foo(x)
  if(x > 5)
    bar = 100
  end
  puts bob
end

Я получаю ошибку "неопределенная локальная переменная или метод".

Итак, мой вопрос: почему я не получаю эту ошибку, когда я вызываю foo (3), а bar никогда не устанавливается?

Ответы [ 5 ]

55 голосов
/ 11 ноября 2010

Здесь происходит пара вещей. Во-первых, переменные, объявленные внутри блока if, имеют ту же локальную область видимости, что и переменные, объявленные на верхнем уровне метода, поэтому bar доступен за пределами if. Во-вторых, вы получаете эту ошибку, потому что на bob ссылаются прямо на ровном месте. Интерпретатор Ruby никогда не видел его и никогда не видел его инициализированным ранее. Однако он видел bar, инициализированный ранее, внутри оператора if. Поэтому, когда он попадает в бар, он знает, что он существует. Объедините эти два, и это ваш ответ.

15 голосов
/ 11 ноября 2010

Ваш второй пример на самом деле - красная сельдь: причина, по которой вы получаете исключение, не в том, что bob неинициализирован, а в том, что он неоднозначен.Невозможно определить, является ли это переменная или метод.

Ваш первый пример работает, потому что неинициализированные локальные переменные (а также глобальные переменные и переменные экземпляра) оцениваются в nil.Следовательно, puts bar совершенно нормально: в одном случае bar инициализируется до 100, и это оценивается как 100, в другом случае оно не инициализируется и, следовательно, оценивается в nil.puts вызывает to_s для своего аргумента, который определен для nil (он просто возвращает пустую строку), так что все в порядке и элегантно.

Смотрите также В Rubyпочему после запуска irb, foo.nil?говорит неопределенную ошибку, а @ foo.nil?дает «правда», а @@ wah.nil?снова выдает ошибку?

4 голосов
/ 11 ноября 2010

Так что не принимайте это как евангелие (поскольку оно больше основано на наблюдении, чем на понимании), но похоже, что интерпретатор ruby ​​помечает любое слово (без символа перед ним) слева от знака равенства как местный. Ваш пример странный, это еще более странно

def foo
  bar = bar
  puts bar // nil, which gets coerced into ""
end

Я не понимаю, почему и как это работает, но у вас это есть.

2 голосов
/ 27 марта 2012

foo(3) не выводит ничего.Он выводит новую строку.

Использование inspect даст вам подсказку:

def foo(x)
  if(x > 5)
    bar = 100
  end
  puts bar.inspect
end

foo(3)

выводит на печать

nil

bar полностьюпеременная fledged, которая, как оказалось, имеет значение nil.

0 голосов
/ 11 ноября 2010

Я не уверен, что вы спрашиваете.Запуск foo(3) со вторым определением всегда выдаст ошибку, поскольку bob никогда не определяется.Аргумент метода не меняет этого.

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