自訂運算子

lua-users home
wiki

Lua 有一組預先定義的運算子 [1],而且沒有內建的功能能夠定義自訂運算子。不過,還是有一些方式可以近似自訂運算子。許多這些方法並不建議使用。

技巧:使用者定義命名運算子 1 號(中綴運算子)

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

技巧:使用者定義命名運算子 2 號(中綴運算子)

這模仿了一個類似的 [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

技巧:使用者定義命名運算子 3 號

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

相關連結


最近的修改 · 喜好設定
編輯 · 歷史記錄
最後編輯日期為 2009 年 5 月 2 日,上午 2:26 格林威治標準時間 (差異)