關于變量和方法的二義性辯論
首先先看個類
[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
但是尚未初始化。