自訂運算子 |
|
Lua 提供一組小運算子,還有一組比較小、你可以覆寫的運算子。<<
運算子通常用於將物件插入 C++ 的輸出串流中,但它不屬於上述兩組運算子。這並不表示我們不能嘗試。以下程式碼顯示了一種範例,我們可以在 Lua 中模擬自訂運算子的定義及使用。
-- Custom operator to evaluate (class) local CustomOp = {} function CustomOp:__div(b) -- eval full operation. return getmetatable(self.a)['__' .. self.op](self.a, b) end setmetatable(CustomOp, {__call = function(class, a, op) -- construct left-half of operation. return setmetatable({a = a, op = op}, CustomOp) end }) function enable_custom_ops(mt) -- enable custom ops on metatable. function mt:__div(op) return CustomOp(self, op) end return mt end -- Output stream (class) ostream = {} ostream.__index = ostream enable_custom_ops(ostream) function ostream:write(s) io.write(s) end ostream['__<<'] = function(self, s) -- '<<' operator self:write(s) return self end setmetatable(ostream, {__call = function(class, file) -- construct output stream file = file or io.output() return setmetatable({file = file}, ostream) end }) cout = ostream() endl = "\n" -- end of line -- example usage local _ = cout /'<<'/ "hello" /'<<'/ endl
--DavidManura,200703
這模仿了一個類似的 [Python 技巧]
local sm = setmetatable local function infix(f) local mt = { __sub = function(self, b) return f(self[1], b) end } return sm({}, { __sub = function(a, _) return sm({ a }, mt) end }) end local shl = infix(function(a, b) return a*(2^b) end) print(5 -shl- 4) --> 80
好棒,對嗎?缺點:每個運算會配置一張資料表。
--MikePall,2007-03-09
local function factorial(n) local y = 1 for i=2,n do y = y * i end return y end local function xor(a,b) assert(a == 3 and b == 4) -- an exercise for the reader! return 7 -- or see https://lua-users.dev.org.tw/wiki/BitUtils end debug.setmetatable(0, { -- create metatable for numbers __call = function(a, op) if op == '!' then return factorial(a) elseif op == 'xor' then return function(b) return xor(a,b) end end end }) print(- (5)'!' + 1, - (3) 'xor' (4)) --> -119 -7
請注意運算子優先順序:這些都是函式呼叫。
對一元後置運算子來說沒有記憶體配置,但二元運算子有。我們可以透過以下方式來改善它(雖然不幸的是,這樣可能造成未定義的行為)
local savea local function xorhelper(b) local a; a, savea = savea, nil return xor(a,b) end debug.setmetatable(0, { __call = function(a, op) if op == '!' then return factorial(a) elseif op == 'xor' then savea = a; return xorhelper end end })
--DavidManura,2007-07-14
cond ? expr1 : expr2
結構