I don't understand ruby local scope
In this example,
def foo(x)
if(x > 5)
bar = 100
end
puts bar
end
Then foo(6) Outputs: 100 and 开发者_Go百科foo(3) outputs nothing.
However if i changed the definition to
def foo(x)
if(x > 5)
bar = 100
end
puts bob
end
I get an "undefined local variable or method" error.
So my question is why I am not getting this error when I call foo(3) and bar is never set?
There a couple of things going on here. First, variables declared inside the if
block have the same local scope as variables declared at the top level of the method, which is why bar
is available outside the if
. Second, you're getting that error because bob
is being referenced straight out of the blue. The Ruby interpreter has never seen it and never seen it initialized before. It has, however, seen bar
initialized before, inside the if statement. So when is gets to bar it knows it exists. Combine those two and that's your answer.
Your second example is actually a red herring: the reason why you are getting an exception is not because bob
is uninitialized, it's because it is ambiguous. It's impossible to tell whether it's a variable or a method.
Your first example works, because uninitialized local variables (as well as global variables and instance variables) evaluate to nil
. Therefore, puts bar
is perfectly fine: in one case bar
is initialized to 100
and this evaluates to 100
, in the other case it is uninitialized and thus evaluates to nil
. puts
calls to_s
on its argument, which is defined for nil
(it simply returns the empty string), so everything is fine and dandy.
See also In Ruby, why after starting irb, foo.nil? says undefined error, and @foo.nil? gives “true”, and @@wah.nil? gives error again?
So don't take this as gospel (since it is more based on observation then understanding), but it seems like the ruby interpreter will flag any word (without a sigil in front of it) to the left of an equals sign as a local. Your example is strange, this is even more bizarre
def foo
bar = bar
puts bar // nil, which gets coerced into ""
end
I don't understand why or how it works, but there you have it.
foo(3)
doesn't output nothing. It outputs a newline.
Using inspect
would give you more of a hint:
def foo(x)
if(x > 5)
bar = 100
end
puts bar.inspect
end
foo(3)
prints out
nil
bar
is a fully-fledged variable, which just happens to have a value of nil
.
I'm not sure what you're asking. Running foo(3)
with the second definition will always give an error, since bob
is never defined. The argument to the method doesn't change that.
精彩评论