关于变量和方法的二义性辩论
首先先看个类
[27] pry(main)* class Person
[27] pry(main)* def current_user
[27] pry(main)* "it from method"
[27] pry(main)* end
[27] pry(main)* def show
[27] pry(main)* puts "1---> #{current_user}"
[27] pry(main)* zz = 123
[27] pry(main)* if false
[27] pry(main)* var_1 = 123
[27] pry(main)* var_2 = nil
[27] pry(main)* current_user = nil
[27] pry(main)* puts "6--->#{zz}"
[27] pry(main)* zz = 2222222
[27] pry(main)* end
[27] pry(main)* puts "2--->#{var_1}"
[27] pry(main)* puts "3--->#{var_2}"
[27] pry(main)* puts "4--->#{current_user}"
[27] pry(main)* puts "5--->#{zz}"
[27] pry(main)* end
[27] pry(main)* end
=> nil
[28] pry(main)> p = Person.new
=> #<Person:0x007fb534ebb6d0>
[29] pry(main)> p.show
1---> it from method
2--->
3--->
4--->
5--->123
=> nil
两个疑问
1、为啥 ‘1’处会有输出,但是‘4’处没有输出?
2、为啥 ‘2’,‘3’ 没有输出?
In Ruby, because methods can be called without an explicit receiver and without parentheses, there is a syntactic ambiguity between a local variable reference and a receiverless argumentless method call:
翻译:在Ruby中,由于方法可以在不明确的接收器和不带括号调用,有一个局部变量的引用和receiverless argumentless方法调用之间就会产生句法歧义:
foo
could either mean "call method foo on self with no arguments" or "dereference local variable foo".
翻译:既可以指“自我调用方法foo不带任何参数”或“间接引用本地变量foo”。
If there exists a local variable foo in scope, this is always interpreted as a local variable dereference, never as a method call.
翻译:如果存在一个局部变量foo的范围,这个总是被解释为一个局部变量解引用,从来没有作为一个方法调用。
So, what does it mean for a local variable to "be in scope"? This is determined syntactically at parse time, not semantically at runtime.
This is very important! Local variables are defined at parse time: if an assignment to a local variable is seen by the parser, the local variable is in scope from that point on.
It is, however, only initialized at runtime, there is no compile time evaluation of code going on:
翻译:那么,是什么意思为一个局部变量要“范围”?这是在分析时确定的语法,语义没有在运行。这是非常重要的!局部变量在分析时定义:如果一个赋值给一个局部变量解析器看出,局部变量的作用域从该点。然而,只有在运行时进行初始化,则代码将在没有编译时评价。
观点:局部变量在解析的时候就确定了,只不过在运行的时候赋值和初始化!并且如果存在同名局部变量和方法名,那么就只会调用局部变量,而不会调用方法。从同名的局部变量定义那会儿开始,往后的都是他的作用域范围。
if false
foo = 42 # from this point on, the local variable foo is in scope
end
foo # evaluates to nil, since it is declared but not initialized
Why does it make sense for local variables to "shadow" methods and not the way around? Well, if methods did shadow local variables, there would no longer be a way to dereference those local variables. However, if local variables shadow methods, then there is still a way to call those methods: remember, the ambiguity only exists for receiverless argumentless methods calls, if you add an explicit receiver or an explicit argument list, you can still call the method:
翻译:为啥局部变量覆盖方法是有意义的,反之呢?好吧,如果方法覆盖了实力变量,那么不会有一种方式来调用这些局部变量。但是,如果局部变量覆盖方法方法,那么还有一个方法来调用这些方法:请记住,模糊只存在于receiverless argumentless方法的调用,如果你明确的添加一个接收器或一个明确的参数列表,你仍然可以调用方法:
def bar; 'Hello from method' end; public :bar
bar # => 'Hello from method'
bar = 'You will never see this' if false
bar # => nil
bar = 'Hello from local variable'
bar # => 'Hello from local variable'
bar() # => 'Hello from method'
self.bar # => 'Hello from method'
综上所述
两个疑问
1、为啥 ‘1’处会有输出,但是‘4’处没有输出?
因为在‘1’位置处,ruby不清楚到底是局部变量,还是方法,所以先找局部变量,然后发现没有定义,所以就找到方法,输出方法的值。
由于Ruby是解释执行,
并且在
if false
...
current_user = nil
...
end
中重新定义了 current_user的局部变量,所以在这之后,都是局部变量current_user的作用域,所以即使是 if flase
,但是还是定义了current_user局部变量。最后根据
If there exists a local variable foo in scope, this is always interpreted as a local variable dereference, never as a method call
所以后面‘4’的位置调用的是局部变量 current_user,而非方法。所以‘4’的位置输出为nil
2、为啥 ‘2’,‘3’ 没有输出?
道理如上,虽然定义了var_1
,var_2
但是尚未初始化。