Lua metatables和metamethod - 如何调用不同的成员函数

Sat*_*hJM 2 oop lua class object metatable

我有以下课程

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 
Run Code Online (Sandbox Code Playgroud)

这样做是当你访问table[key]它时执行查找table.__group(这是另一个类的对象)并返回table.__group[key],如果它不是nil.

现在我正在为成员函数做同样的事情.即如果我调用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 
Run Code Online (Sandbox Code Playgroud)

但这里有两件事是错的.

  1. 我无法检索原始函数的参数
  2. 事件,如果我只是ACCESS table[key].function没有调用它,该函数将被调用

我感觉我正在努力使事情复杂化,解决方案更简单.

任何帮助表示赞赏.

UPDATE

@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
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,progress_object:showSum(3,3)调用When时 ,是否可以将group_object(或者换句话说progress_object .__ group)作为self而不是progress_object传递.

希望有道理.

Mud*_*Mud 6

对更新后的回复:

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

如果你要忽略一个方法被调用的对象的状态,并替换一些其他对象的状态,为什么它甚至是该对象的方法?这就像重写加法运算符来进行乘法运算一样,这是一种混淆的方法.

换句话说,你想要这个:

progress_object:method("foo")
Run Code Online (Sandbox Code Playgroud)

通过奇怪的内部机器解决这个问题:

group_object:method("foo")
Run Code Online (Sandbox Code Playgroud)

为什么不跳过一步而只是拨打后一个电话呢?

如果你一定要,你可以通过它取代了方法返回的代理实现这一目标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
Run Code Online (Sandbox Code Playgroud)

回复原帖:

我如何尝试为成员函数做同样的事情.即如果我调用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
Run Code Online (Sandbox Code Playgroud)

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

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

foo:showSum(3,3) -- 6
foo:showProduct(3,3) -- 9
Run Code Online (Sandbox Code Playgroud)

而已.



现在,只要我们在这里,让我们来看看你的第二个功能在做什么:

     local val = self.__group[key]
     if type(val) == "function" then 
         self.__group:val()
         return function() end 
     end
Run Code Online (Sandbox Code Playgroud)

首先从中获取函数值__group.此时你已经完成了.只需返回该值,调用者就会调用该值(即(...)).相反,你调用__group["val"]哪个可能是一个完全不同的函数__group[key](除非键=="val"),然后你传递给调用者一个什么都不做的函数.