Lua 参考指南中的元表

我现在有一个相当令人费解的设定。我有一个普通函数,它返回一个带有“字符串”和“数字”键下函数的表格:

function defGeneric()
    local function funcNumber(a)
        return 2*a^2
    end
    local function funcString(a)
        return a.." - 测试"
    end
    local returnTable={}
    returnTable["number"]=funcNumber
    returnTable["string"]=funcString
    return returnTable
end

这样就可以正常工作。但我现在想做的是让这个函数返回的表格可调用。为了说明,假设我们有 v=defGeneric()。具体地说,

  1. 如果使用字符串 str 调用 v,将返回 v["string"](str) 的结果
  2. 如果使用数字 n 调用 v,将返回 v["number"](n) 的结果

这显然是元表的工作,所以我可以在我的函数中添加设置元表的代码:

local metaTable = {
        __call = function (...) -- "call" 事件处理程序
            return
        end
    }
setmetatable(returnTable,metaTable)

但我不知道在那个 return 语句之后应该放什么。我认为我不能引用 returnTable,因为这个表将被这样调用:

v=defGeneric()
v("测试")

而且我需要引用 v 的“字符串”函数(在一个程序中肯定会有多个 defGeneric() 表格)。

我想这里的答案可能是一些 self 技巧,但我想不出头绪。我怎样从元表中引用表?

点赞
用户369792
用户369792

__call 函数接受的第一个参数是被调用的表格,也就是本例中返回的函数的表格。你可以使用 type(a) 获取参数的类型(字符串形式),因此你可以这样做:

function defGeneric()
  local result = {
    ['number'] = function(a) return 2*a^2 end,
    ['string'] = function(a) return a.." - test" end
  }
  setmetatable(result, {
    __call = function(t,a)
      local f = t[type(a)]
      if f == nil then return "No handler for type "..type(a) end
    -- 可替换为:
    -- if f == nil and t['string'] ~= nil then return t['string'](tostring(a)) end

      return f(a)
    end
  })
  return result
end

local def = defGeneric()
print("string: "..tostring(def('sample string')))
print("number: "..tostring(def(5)))
print("table: "..tostring(def({})))
print("boolean: "..tostring(def(1 > 5)))

输出:

string: sample string - test
number: 50.0
table: No handler for type table
boolean: No handler for type boolean

或者替换后的输出:

string: sample string - test
number: 50.0
table: table: 0x18537e0 - test
boolean: false - test
2018-06-06 13:42:51