Я не понимаю рубинский локальный охват
В этом примере
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), и бар никогда не устанавливается?
Ответы
Ответ 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
никогда не определяется. Аргумент метода не меняет этого.