试图用metatables创建一个lua代理

时间:2016-11-03 00:19:49

标签: lua hook metatable

我已经阅读了有关元数据(herehere)的内容,我问自己是否可以通过向__index添加具有相同名称的函数来创建函数调用代理表,以便它调用索引函数(我的),然后我可以调用正常函数。

这是我尝试过的:

local test = {}
test.static = function () print("static") end -- The normal function

local old = getmetatable(test) or {} -- Get the orginal meta
old.__index = {
    static = function () print("hook") end -- Adding my function
}

test.static() -- call just for test ( prints -> static )
test = setmetatable( test , old ) -- setting the metatable
test.static() -- call just for test ( prints -> static, but should be hook )

1 个答案:

答案 0 :(得分:0)

尝试给official source一个读物,特别是§2.4 – Metatables and Metamethods,以及__index甲基方法的描述,内容如下:

  
      
  • __ index :索引访问table[key]。当表不是表或表中没有键时,会发生此事件。 metame方法在表格中查找。

         

    尽管名称,此事件的元方法可以是函数或表。如果它是一个函数,则使用table和key作为参数调用它,并且调用的结果(调整为一个值)是操作的结果。如果是表,则最终结果是使用键索引此表的结果。 (这种索引是常规的,而不是原始索引,因此可以触发另一种元方法。)

  •   

我们可以看到你的想法是倒退的。仅当原始表不包含密钥时,才会查找__index元方法引用的表上的属性。

如果你想“挂钩”一个功能,你需要覆盖它,可能会保存原件以便以后恢复它。如果你想在函数上使用现有函数,你可以编写一个简洁的小挂钩函数,它只是在函数周围创建一个闭包,依次调用它们。

local function hook (original_fn, new_fn)
    return function (...)
        original_fn(...)
        new_fn(...)
    end
end

local test = {}
test.foo = function () print('hello') end
test.foo = hook(test.foo, function () print('world!') end)

test.foo() --> prints 'hello' then 'world!'

或者,您可以在元表之间切换,假设原始表永远不会覆盖感兴趣的键,以获得不同的结果:

local my_table, default, extra = {}, {}, {}

function default.foo () print('hello') end

function extra.foo() print('world!') end

local function set_mt (t, mt)
    mt.__index = mt
    return setmetatable(t, mt)
end

set_mt(my_table, default)
my_table.foo() --> prints 'hello'
set_mt(my_table, extra)
my_table.foo() --> prints 'world!'