資料表函數 2 |
|
為了效率,這有一定限制,即私人金鑰無法為值 nil
(將私人金鑰設為 nil 會發佈金鑰)。由於有了 false
,所以我認為這沒那麼關鍵。(好啦,也許 false
並不是個壞主意 :))
有趣的是,公共狀態資料表中沒有保留金鑰,而且客戶程式可以自由使用剛好為私人的金鑰。在這個案例中,客戶程式和資料表函數會看到不同的資料表。
我沒有放入口承,但那並不難。私人資料表在嘗試公共資料表前,需要先檢查其繼承自物件的私人資料表,而且公共資料表僅有一個 __index
元方法,其值為同一個物件的公共資料表。這比較像物件原型化,而不是類別繼承,但通常是實用的程式設計風格。
do -- the private table just forwards to the public table. local private_meta = { __index = function(t, k) return t.__public[k] end, __newindex = function(t, k, v) t.__public[k] = v end, __call = function(t, ...) return t.__function(t, unpack(arg)) end } function Tablefunc(fn, private) -- this is what the caller will see local public = {} -- remember what we do and where we do it private.__function = fn private.__public = public -- normally I'm not in favour of privatisation, but -- sometimes you have to do it. -- Call this as follows: -- self:privatise {private_key = initial_value, -- other_private_key = initial_value} function private.privatise(self, vars) for k, v in vars do rawset(self, k, v) end end -- set up the deferral metamethods setmetatable(private, private_meta) -- create a new metatable with a __call metamethod which -- accesses the private table through a closure. return setmetatable(public, { __call = function(t, ...) return private.__function(private, unpack(arg)) end }) end end
讓我們來試試看。
function test(self, x) if x then self:privatise({public = "public hidden"}) end print("hidden:", self.hidden) print("public:", self.public) end
$lua Lua 5.0 (beta) Copyright (C) 1994-2002 Tecgraf, PUC-Rio > a = Tablefunc(test, {hidden = "hidden"}) > a() hidden: hidden public: nil > a.public = "public" > a() hidden: hidden public: public > a.hidden = "change hidden" > a() hidden: hidden public: public > = a.hidden change hidden > -- here we tell the function to make "public" private > a(1) hidden: hidden public: public hidden > = a.public public > a.public = "change public" > a() hidden: hidden public: public hidden > = a.public change public
--RiciLake