在Lua中,我如何知道一个表是否包含一个类函数?

假设我使用“:”操作符声明了一个 Lua 函数,如下所示:

function ClassName:myFunc( stuff )
    --do stuff
end

然后,我将该函数存储在表中,如下所示:

someTable = {
    ClassName.myFunc,
    someGlobalFunc,
}

接着,假设我有另一个函数遍历表并尝试调用其中给定的函数。

function ClassName:callStuffInThisTable(table)
    --我遍历表,可能是上面的 someTable,并调用所有函数
end

我的问题是,如何知道在表中的函数是否为 ClassName 的所有,以便我可以使用 self 调用它?

原文链接 https://stackoverflow.com/questions/10020605

点赞
stackoverflow用户734069
stackoverflow用户734069

你不会知道的。至少,在Lua看来,function ClassName:myFunc(stuff)只是语法糖。它与ClassName.myFunc = function(self, stuff)没有任何区别。这些函数是等价的。

同样对于:调用语法ClassName:myFunc(stuff)在语义上等价于ClassName.myFunc(ClassName, stuff)

你需要知道你的函数是什么以及它们做什么。这需要编程纪律。如果你有一个需要在循环中调用的函数列表,那么它们应该被设计成使用相同的参数调用。

有两种方法可以做到这一点。一种方法是使所有函数成为“类函数”:

someTable = {
    ClassName.myFunc,
    function(self, ...) return someGlobalFunc(...) end,
}

这样,self参数就被忽略了。显然,你可以创建一个特殊的函数表对象,其中包含用于插入“全局”函数到表中的函数,这些函数将自动生成包装器:

function insertFuncIntoTable(self, func)
  self[#self + 1] = function(self, ...) func(...) end
end

insertFuncIntoTable(someTable, someGlobalFunc)

注意:假设“someGlobalFunc”实际上是全局表的成员(而不是local),那么这些版本之间存在差异。这个版本将采取_G["someGlobalFunc"]目前具有的值,就像你的原始代码一样。然而,第一个版本将采取调用时它所具有的值,这可能是一个不同于在创建someTable时的函数。

因此,这个版本更安全。

或者,你可以使表中任何“类函数”都明确地绑定到一个对象实例:

someTable = {
    function(self, ...) ClassName.myFunc() end,
    function(self, ...) return someGlobalFunc(...) end,
}

顺便说一下,一般来说,如果你使用:语法来声明一个函数,你应该通过instance:myFunc(...)这种方式来使用它。显然,它只是一个像其他Lua函数一样的函数,所以你可以用你喜欢的方式做。但是错误使用可能会使理解正在发生的事情变得更加困难。

Lua为你提供了很多力量。但你在编程时仍需要行使判断力和纪律。Lua不能完全拯救你(否则完全是另一回事)。

2012-04-04 23:36:23
stackoverflow用户221955
stackoverflow用户221955

一种检查函数是否由 ClassName 拥有的方法是进行扫描和检查。

ClassName = {}
function ClassName:fn(self) ... end

t = { function() ... end , ClassName.fn() }

function has_value( klass, value )
  for k,v in pairs(klass) do
    if v==value then return true
    end
    return false
  end
  
function ClassName:callStuffInThisTable(table)
  for k,v in pairs(table) do
    if has_value(ClassName, v) then
      v(self)
    else
      v()
    end
  end
end

由于表扫描,这会导致 O(n^2) 的行为。通过使用 ClassName 中的函数作为一个新表,我们可以将其减少到 O(n log(n))。

function ClassName:callStuffInThisTable(table)
  local t = {}
  for k,v in pairs(ClassName) do
    t[v] = 1
  end

  for k,v in pairs(table) do
    if t[v]==1 then
      v(self)
    else
      v()
    end
  end
end
2012-04-05 01:16:56