2010-04-29 62 views
2

似乎在像C,Java和Ruby這樣的語言(而不是Javascript)中,爲循環塊的每次迭代創建一個新的作用域,並且爲循環定義的局部變量實際上被製作爲一個局部變量單一時間並記錄在這個新的範圍內?在每次在循環塊中創建新範圍的語言中,本地循環變量的新本地副本是每次在新範圍內創建的?

例如,在Ruby中:

p RUBY_VERSION 

$foo = [] 

(1..5).each do |i| 
    $foo[i] = lambda { p i } 
end 

(1..5).each do |j| 
    $foo[j].call() 
end 

打印出來是:

[MacBook01:~] $ ruby scope.rb 
"1.8.6" 
1 
2 
3 
4 
5 
[MacBook01:~] $ 

因此,它看起來是創建一個新的範圍時,也創造了i新的本地副本一樣並記錄在這個新的範圍內,以便稍後執行該功能時,在這些範圍鏈中分別找到「i」分別爲1,2,3,4,5。這是真的? (這聽起來像一個沉重的操作)。

對比度與

p RUBY_VERSION 

$foo = [] 

i = 0 

(1..5).each do |i| 
    $foo[i] = lambda { p i } 
end 

(1..5).each do |j| 
    $foo[j].call() 
end 

這一次,i在進入循環之前因此Ruby 1.8.6不會把這個i在用於循環塊創建的新範圍,因此,當所定義的, i在作用域鏈擡頭一看,它總是指i這是在外面的範圍,並給予5每次:

[MacBook01:~] $ ruby scope2.rb 
"1.8.6" 
5 
5 
5 
5 
5 
[MacBook01:~] $ 

我聽說在Ruby 1.9中,i WIL l即使有前面定義的i,我也會將其視爲爲循環定義的本地?

創建一個新範圍的操作,每次循環創建一個新的本地副本i看起來很重,因爲如果我們稍後不調用這些函數,似乎沒有問題。因此,當函數不需要在以後調用時,解釋器和編譯器能否使C/Java嘗試優化它,以便每次都不存在本地副本i

回答

1

這與此處討論的主題類似:http://math.andrej.com/2009/04/09/pythons-lambda-is-broken/。在一些編程語言中,當你循環一個變量時,循環結構的主體被綁定到一個增量變量。在其他情況下,每循環迭代一個新的循環變量被實例化。

至於詞法範圍,請注意,在JavaScript中,函數是構成範圍的唯一結構(括號爲ifwhilefor等等)。在C/C++中,任何一對大括號構成一個範圍。