Подтвердить что ты не робот

Я не понимаю рубинский локальный охват

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

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

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

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

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

Ответ 3

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

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

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

Ответ 4

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

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

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

foo(3)

выводит

nil

bar - это полноценная переменная, которая просто имеет значение nil.

Ответ 5

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