【问题标题】:Lua metatables and metamethod - How to call a different member functionLua 元表和元方法 - 如何调用不同的成员函数
【发布时间】:2012-06-29 06:24:36
【问题描述】:

我有以下课程

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[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. 如果我只是 ACCESS table[key].function 而不调用它,就会调用该函数

而且我有一种感觉,我试图使事情复杂化,而解决方案要简单得多。

感谢任何帮助。

更新

@泥 原始代码的问题在于,作为“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)作为self而不是progress_object传递。

希望这是有道理的。

【问题讨论】:

    标签: oop class object lua metatable


    【解决方案1】:

    对更新帖子的回应:

    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
    

    就是这样。



    现在,只要我们在这里,让我们看看你的 second 函数在做什么:

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

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

    【讨论】:

    • 啊!很有意义。有时我想太多 :D 非常感谢!
    • 嘿。原代码有一个小问题。已更新问题。你能帮忙吗?顺便说一句,这就是我发布这个问题的原因。当我阅读您的答案时忘记了问题:P
    • 很好解决!太感谢了!对不起,如果这个问题听起来很扭曲。在构建特定类时,我只是在玩弄 Lua! :) 再次感谢!
    • @SatheeshJM:更新了代码,因此它不会吃掉非方法调用的参数。
    猜你喜欢
    • 1970-01-01
    • 2011-03-08
    • 2015-11-05
    • 1970-01-01
    • 2016-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-23
    相关资源
    最近更新 更多