Lua 範圍討論 |
|
VersionNotice:在此頁面上的留言指涉 Lua 的舊版本(2001 年),它有更多受限的詞彙範圍且據稱不完全支援封閉。在近期版本中,這些留言許多都不適用。
Lua 採取靜態範圍 [1]。
對於這種情況是否應稱做受限/錯誤靜態/詞彙範圍,有些分歧。一些電腦語言文字將詞彙範圍和靜態範圍定義成相同的,讓事情變得複雜。當存取到的變數位於全域範圍時,Lua 的作用就像詞彙範圍。
do -- assume "a" is a global with value 5 local foo = function() print(a) end a = 10 foo() -- prints "10" end
當使用 upvalues 存取下一個外部範圍時,Lua 也像詞彙範圍一樣作用,只要不會將變數重新繫結(從變數範圍或巢狀函式重新繫結)。
do local a = 5 local foo = function() print(%a) end foo() -- prints "5" end
無論如何,與 Perl 等其他腳本語言年輕時相比,Lua 或許並不如它們那麼糟。Perl 從動態範圍做起,已慢慢發展成透過 my
限定條件來支援詞彙範圍。詞彙範圍可能會在 Perl 6 中成為預設值。
Python 以前有和 Lua 類似的受限靜態範圍。詞彙範圍會在 2.2 版中成為預設值,而且在 2.1 版中已成為一個選項 [2]。Python 實作的詞彙範圍不允許從巢狀函式中重新繫結變數,這類似於 Lua 的 upvalues。
對於 Lua,可能只需要將其受限子組擴充為真正的詞彙範圍即可。它可以延續 upvalue 的概念,而不允許重新繫結,就像 Python 一樣。或者也可以允許重新繫結,並消除 upvalues 的需求,而 upvalues 常常是 Lua 程式設計師混淆的來源。在 Python 詞彙範圍的設計文件中,引言不允許重新繫結的主要原因是 Python 沒有變數宣告。由於 Lua 需要 local
來限定變數,因此這不會是個問題。
-- E. Toernig
來自「編譯器,原理、技術,與工具」,Aho、Sethi,與 Ullman,1986 年,艾迪生魏斯理
將 FOLDOC 條目與龍書中的內容進行比較,後者的定義看起來稍微寬鬆,因為沒有提出「最小的區塊」規範是必要的,而且只提到那是某些語言(例如 C)的性質。換句話說,一個給定的範圍規則不需要是動態的(也就是說,不需要依賴目前的啟動狀態)才被視為靜態就夠了。
在 Lua 語言中,每個變數都具有區域或全域的範圍。可以在函數內定義函數,但巢狀函數無法取用其任何包函函數中定義的變數。因此,Lua 變數缺乏靜態巢狀範圍。造成此一結果,下列 Lua 程式碼是不合法的
function addn(x) function sum(y) return x+y end return sum end print((addn(3))(1))
此範例會不合法,因為在 addn 中定義的變數 x 不可以被巢狀函數 sum 取用。
巢狀函數可以取用其最直接包函函數中定義的變數的副本。在函數中取用變數的 upvalue 參考會在評估函數以產生閉包時提取此副本。一個變數在 percent 符號之前帶有一 percent 符號表示一個 upvalue 參考。在 sum 中 x 參考之前加上一個百分比符號,讓上述範例成為合法的 Lua 程式碼。
這項用於替代靜態巢狀範圍的糟糕做法已被採用,這是因為它很容易產出一個所有非全域變數都已堆疊分配的程式,但需要放棄靜態巢狀範圍才能有堆疊分配的非全域變數。
在 Python 2.2 版本以前的 Python 語言 دارای與 Lua 現有規則類似的範圍規則,每個變數都具有區域或全域的範圍。從 2.2 版本開始,Python 具有靜態巢狀範圍。在 Python 的程式碼實作中,從巢狀函數中參考的非全域變數是不變的。在此額外假設下,堆疊分配的非全域程式碼很容易被實作。
Python 的程式碼實作驗證了此方法的有效性。根據 Luca Cardelli 在 1984 年一篇名為「編譯函數語言」的論文中所述的內容,他們使用了平面式閉包程式碼,因而具備快速實作[3]。相關部分是關於「取用變數」的第 4 部分。
對於我們這些希望未來版本的 Lua 能夠具有具有靜態巢狀範圍的變數的人,我建議我們可以的幫助方法是尋找 Lua 核心實作人員可以使用的方法來進行程式碼實作。我認為我們應仔細研究 Python 2.2 實作中相關部分的點子,並將其提供給他們。
我相信用一種優秀的非常高級的程式語言撰寫的程式,對於不太熟悉該語言的人而言,是很容易就能理解的。除了上層值之外,我想 Lua 在這方面做得很好,因為它採用了類 Pascal 的語法用於控制結構,其意義正是大家所預期的。使用上層值的程式,不太可能讓一般使用者理解。人們需要閱讀手冊才能理解它們在哪裡取得值。大部分人直覺上都能理解靜態巢狀範圍。在從巢狀函式內參照變數時,讓變數變成不可變更,會為 Lua 程式的作者帶來負擔,但對程式的閱讀者而言則不然。我認為 Lua 的設計應優先滿足閱讀者的需求。
以下為靜態巢狀範圍的定義
-- 約翰·D·拉姆斯戴爾