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(这是另一个类的对象)中执行查找,如果它不是 nil,则返回 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原始代码的问题在于,作为"self"传递给成员函数的对象是新类的对象。不属于旧阶级。

考虑此代码

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)作为自身而不是progress_object传递。

希望这是有道理的。

对更新帖子的回应:

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 不知道什么是"成员函数"。成员是成员(即表中的元素),该成员的值是否为函数无关紧要。

记得:

  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]
     if type(val) == "function" then 
         self.__group:val()
         return function() end 
     end

首先,您从 __group 中获取函数值。至此,您已完成。只需返回该值,调用方将调用该值(即 (...))。相反,你调用__group["val"]它可能是一个与__group[key]完全不同的函数(除非key=="val"),然后你向调用者传递一个什么都不做的函数。

最新更新