我是 Lua“類”(元表)的新手,我有疑問。
在我撰寫的以下建構式代碼中,我將變數宣告obj為local. 但是在網路上的大多數示例中,這個變數只是被分配給沒有local宣告。所以在我的理解中,它變成了一個全域變數(從我的理解來看效率不高)。但這有什么原因嗎?
A = {}
A.__index = A
function A:new(obj_init)
local obj = obj_init or {val = 0}
setmetatable(obj, A)
return obj
end
我還注意到可以直接訪問該類的成員,甚至可以從另一個 Lua 模塊訪問:
x = A:new{val = 2}
print(x.val)
但是有沒有辦法讓val一個私人成員?也許也使用local?
uj5u.com熱心網友回復:
首先,讓我們看看您找到的這些示例可能是什么樣子。
引數:隱式區域變數
function A:new(obj)
obj = obj or {val = 0}
...
end
在這個片段中,obj是一個區域變數。這是因為 Lua 中的所有函式引數都是區域變數。我們可以重寫函式如下來強調這一點:
function A:new(...)
local obj = ...
obj = obj or {val = 0}
end
我假設這就是你在 PIL 中看到的。您可能將引數重命名為obj_init,從而丟失了obj.
全域分配
如果您碰巧消耗了特別糟糕的資源,您可能會看到以下內容:
function A:new(obj_init)
obj = obj_init or {val = 0}
...
end
在這個片段中,obj確實是一個全域變數。由于多種原因,這非常糟糕:
- 效率:你是對的——除了病態的情況,全域變數總是比區域變數慢,因為全域變數是表(哈希部分)中的條目,而區域變數
_G存盤在 Lua VM 的快速暫存器中。 - 代碼質量:全域污染:這個建構式現在有一個副作用:它修改了全域變數
obj并期望它在執行期間不會被修改。這可能會導致該函式覆寫全域變數obj,更糟糕的是,您現在可能無法從建構式中的協程中產生,因為您依賴于可能無法更改的全域狀態。
私人會員
在 Lua 中實作私有表欄位的典型方法是按照約定:您可以在欄位名稱前加上下劃線,以表明這些欄位不能從外部修改。當然,程式員可以自由地規避這一點。
否則,“私有”變數的概念與 Lua 的腳本語言特性不太吻合。您可以使用元表將成熟的 OOP 硬塞到 Lua 上,但這既不慣用也不高效。
升值
在 Lua 中實作私有成員最慣用的方法是讓它們成為閉包(“訪問器”)的升值:
A = {}
A.__index = A
function A:new(obj_init)
local obj = {} -- empty object: only member is private
local val = obj.val
-- note: this does not need `self`, thus no `:` is used;
-- for setters you might want to discard `self` for consistency
function obj.getVal()
return val
end
setmetatable(obj, A)
return obj
end
x = A:new{val = 2}
print(x.getVal())
-- val can not be set from outside (excepting the debug library);
-- it is "private" and only accessible through the getter method
缺點是所有訪問私有成員的函式都必須在每次創建物件時實體化。
請注意,即使 upvalues 也不是完全“私有的”,因為它們可以通過除錯庫訪問。
debug庫解決方法
該debug庫允許您檢查堆疊。這使您可以判斷哪個方法觸發了您的__index元方法。因此,您可以將不同的值回傳給不同的呼叫者。這對于展示 Lua 的元編程能力的概念驗證來說可能很好,但在實踐中不應該這樣做,因為它非常低效和 hacky。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/532191.html
標籤:班级lua
