Lua/Luajit: 同时使用索引和命名方法?

Lua PILLuajit FFI 教程 中讲了 __index 在元表中的两种用法。

其中一种是索引,比如 obj[123],例如,

__index = function (self, k) return self._data+(k-self._lower)

另一种用法是定义命名方法,如教程中所示,

__index = { area = function(a) return a.x*a.x + a.y*a.y end, },

我们可以像这样调用函数 obj:area()

我可以同时进行直接索引和命名方法吗?

点赞
用户234091
用户234091

答案,通常在 Lua 中的有趣代码中,需要使用更多元表。

__index 元方法实际上是一个表时,Lua 只是在给定表上进行标准表访问。这意味着您可以在您的元表上设置一个元表。然后您可以在这个“元-元表”上设置一个 __index 元方法。

foo = function()
  print("foo")
end

bar = function(_, key)
  return function()
    print(string.format("bar: %s", key))
  end
end

mmt = { __index = bar }
mti = { foo = foo }
mt = { __index =  mti }
t = {}

setmetatable(mti, mmt)
setmetatable(t, mt)

t.foo()  -- 输出:"foo"
t.bar()  -- 输出:"bar: bar"
t.baz()  -- 输出:"bar: baz"

通过这种方式,当您尝试访问两个表中都不存在的字段时,lua 会首先尝试访问顶层表,它将访问第一个元表,然后调用第二个元表的您的元方法。


也有另一种可能更直接的答案:使用您的 __index 元方法来检查另一个表中是否有命名字段:

foo = function()
  print("foo")
end

f = { foo = foo }

bar = function(_, key)
  if f[key] then return f[key] end
  return function()
    print(string.format("bar: %s", key))
  end
end

mt = { __index =  bar }
t = {}

setmetatable(t, mt)

t.foo()  -- 输出:"foo"
t.bar()  -- 输出:"bar: bar"
t.baz()  -- 输出:"bar: baz"

在 Lua 5.3 上测试。

2018-10-30 01:32:59