Lua元表和元方法 - 如何调用不同的成员函数

我有以下的类:

local PROGRESS = {}

PROGRESS.__index = function(self,key)

    if key~="__group" and self.__group[key] then
        return  self.__group[key]
    else
        return rawget(self,key)
    end
end

当你访问 table[key] 时,它会在 table.__group 中执行一次查找(table.__group 是另一个类的对象),如果它不是空值,则返回 table.__group[key]

现在我想为成员函数做同样的事情。也就是说,如果我调用 table:key() ,则必须在 table.__group 中执行查找,如果该函数存在,则应调用 table.__group:key()

我该如何实现它呢?

我尝试做如下操作:

local PROGRESS = {}

PROGRESS.__index = function(self,key)

   if key~="__group" and self.__group[key] then

     local val = self.__group[key]
     if type(val) == "function" then
         self.__group:val()
         return function() end
     end

     return  self.__group[key]
   else
     return rawget(self,key)
   end
end

但有两件事情是错误的。

  1. 我无法获取原始函数的参数
  2. 即使我只是访问 table[key].function 而没有调用它,该函数也会被调用。

我觉得我在试图把事情复杂化,解决方案应该更简单。

任何帮助都将不胜感激。

更新

@ Mud

原始代码的问题在于传递给成员函数的对象是新类的对象,而不是旧类的对象。

考虑此代码

GROUP_CLASS = {}
GROUP_CLASS.__index = GROUP_CLASS
function GROUP_CLASS:showSum(a,b) print(self);print(a + b) end

group_object = setmetatable({},GROUP_CLASS)
group_object:showSum(1,2)

local PROGRESS_CLASS = {}
PROGRESS_CLASS.__index = function(self,key,value)
    if key~="__group" and self.__group[key] then
        return self.__group[key]
    else
        return rawget(self,key)
    end
end

progress_object = setmetatable( {__group = group_object} , PROGRESS_CLASS)
progress_object:showSum(3,3)
--progress_object is passed as first argument to showSum.  But i need group_object to be passed

在上面的代码中,当调用 progress_object:showSum(3,3) 时,是否可能将 group_object(也就是 progress_object.__group)作为 self 传递,而不是 progress_object

希望有意义。

点赞
用户501459
用户501459

回应更新过的帖子:

progress_object作为第一个参数传递给showSum。但我需要传递group_object

如果您要忽略调用方法的对象的状态,并替换为其他对象的状态,那么为什么它甚至是该对象的方法?这就像覆盖加法运算符以执行乘法,这是一种混淆的方法。

换句话说,您希望这样做:

progress_object:method("foo")

通过奇怪的内部机制解决,变成这样:

group_object:method("foo")

为什么不跳一步直接进行后者的调用呢?

如果您必须这样做,则可以通过返回替换“self”为“__group”的方法的代理来实现

local PROGRESS_CLASS = {}
PROGRESS_CLASS.__index = function(self, key)
  local groupval = self.__group[key]
  if key == '__group' or not groupval then
    return rawget(self, key)
  elseif type(groupval) ~= 'function' then
    return groupval
  else
    return function(...)
      if self == ... then -- method call
        -- replace self argument with __group
        return groupval(self.__group, select(2, ...))
      else
        return groupval(...)
      end
    end
  end
end

回应原帖子:

我如何为成员函数做同样的事情。即,如果我调用table:key(),则必须在table.__group中进行查找,如果函数存在,则应调用table.__group :key()。实现这一点的方法是什么?

什么也不用做。您原来的代码已经处理了这个问题。

Lua不知道什么是“成员函数”。成员是成员(即表中的元素),而成员的_value_是否为函数无关紧要。

请记住:

  1. obj:method(a,b,c)等同于obj.method(obj,a,b,c)
  2. obj.method等同于obj ["method"]
  3. 您的代码已将obj ["method"]解析为obj.__group ["method"]

所以你完成了。

例如,假设我们有:

group = {}
function group:showSum    (a,b) print(a + b) end
function group:showProduct(a,b) print(a * b) end

使用您的第一个代码,我们可以编写:

foo = setmetatable({__group = group},PROGRESS)

foo:showSum(3,3)-6 foo:showProduct(3,3)-9

就这样。



现在,只要我们在这里,让我们看看您的第二个函数正在做什么:

local val = self.__ group [key]
如果type(val)==“functionthen
self.__groupval()
返回function()end
end

首先,从__group获取函数值。在这一点上,你已经完成了。只需返回该值,调用方将调用该值(即(...))。相反,您调用了__ group [“val”],这很可能是与__group [key](除非 key==“val”)完全不同的函数,然后将调用者传递给一个什么都不做的函数。

2012-06-27 22:53:49