如何在Lua中更改表的元表但继承其自身的方法

时间:2018-06-28 14:08:39

标签: lua metatable

在Lua中,我们像这样进行OO编程:

MyClass = {}

function MyClass:new()
    local obj = {}
    setmetatable(obj, self)
    self.__index = self

    obj.hello = "hello world"

    return obj
end

function MyClass:sayHi()
    print(self.hello)
end

function main()
  local obj = MyClass:new()
  obj:sayHi()
end

在处理更多compelx内容时,通常我会利用Lua的元方法来代理函数调用,并通过添加以下内容来完成我需要做的事情,例如参数解析等:

MyClassMeta = {}

function MyClassMeta.__index(obj, funcName)
    return function (self, ...)
        //do some stuff
        print("you called " .. funcName .. " with args", ...)
    end
end

并更改行:

setmetatable(obj, self)

收件人:

setmetatable(obj, MyClassMeta)

我使用MyClass实例调用的每个函数都将执行在MyClassMeta.__index元方法中实现的代码。

我现在想做的是继承MyClass现有方法,并仅对不属于MyClassMeta.__index的函数执行MyClass

在上面的示例中,即使调用MyClassMeta.__index,代码也会始终执行MyClass:sayHi()元方法:

function main()
  local obj = MyClass:new()
  obj:sayHi("hello")
end
  

您通过args打了个电话“ hiyHi”

1 个答案:

答案 0 :(得分:1)

__index设置为表时,它将在该表上查找属性,如果实例中不存在这些属性,则将其返回。由于sayHi存在于MyClass表中。

self.__index = self

__index设置为一个函数时,它可以为实例上不存在的属性返回任何内容。您可以检查键是否存在于MyClass表上并返回它,如果不存在,请执行其他操作:

MyClass = {}

MyMetatable = {
  __index = function(obj, key)
    if MyClass[key] ~= nil then return MyClass[key] end
    return function(self, ...)
      print("you called "..tostring(key))
      print("  self.hello is '"..tostring(self.hello).."'")
      print("  with args", ...)
    end
  end
}

function MyClass:new()
    local obj = {}
    setmetatable(obj, MyMetatable)

    obj.hello = "hello world"
    return obj
end

function MyClass:sayHi()
    print(self.hello)
end

function main()
  local obj = MyClass:new()
  obj:sayHi()
end

local obj = MyClass:new()
obj:sayHi("hello")
obj:somethingElse(1, 2, 3)

带有Egor评论的版本

MyClass = {}

setmetatable(MyClass, {
  -- if it's not found on MyClass, return a function
  __index = function(self, funcName)
    return function(self, ...)
      print("you called "..funcName.." with args", ...)
    end
  end
})

function MyClass:new()
  local obj = {}
  -- if it's not found on obj, try self (MyClass)
  setmetatable(obj, { __index = self })
  obj.hello = "hello world"
  return obj
end

function MyClass:sayHi()
    print(self.hello)
end

local obj = MyClass:new()
obj:sayHi()
obj:somethingElse(1, 2, 3)

在创建对象时,这会将新对象的元表的__index设置为MyClass,并将MyClass的元表的索引设置为后备功能。因此,如果该属性不在MyClass上的对象上,它将使用后备。