知道是否可以调用值

时间:2011-09-26 03:09:32

标签: lua

请注意,这个问题与纯Lua有关。我无权访问任何模块或C端。另外,我不能使用IO,OS或调试库。

我想要做的是一个接收的函数,作为参数:

  • 一个数字,是第二个
  • 可调用值

'可调用值',我的意思是可以调用的值。这可以是:

  • 一个功能
  • 一个带有metatable的表,允许调用(通过__call metamethod)

以下是可调用表的示例:

local t = {}
setmetatable(t, {
  __call = function() print("Hi.") end
})
print(type(t)) --> table
t() --> Hi.

这是功能:

function delay(seconds, func)
  -- The second parameter is called 'func', but it can be anything that is callable.
  coroutine.wrap(function()
    wait(seconds) -- This function is defined elsewhere. It waits the ammount of time, in seconds, that it is told to.
    func() -- Calls the function/table.
  end)()
end

但我有一个问题。如果参数'func'不可调用,我希望函数抛出错误。

我可以检查它是否是一个功能。但是如果它是一个带有metatable的表允许调用呢? 如果表的metatable不受__metatable字段的保护,那么,我可以检查metatable以确定它是否可调用,但是,否则,我该怎么做?

请注意,我还考虑过尝试使用pcall调用'func'参数来检查它是否可调用,但为了做到这一点,我需要提前调用它。

基本上,问题在于:我需要知道函数/表是否可调用,但不试图调用它。

3 个答案:

答案 0 :(得分:4)

一般来说,如果metatable不希望你能够得到它(通过将__metatable定义为特殊的东西),那么你就不会得到它。不是来自Lua。

但是,如果你想作弊,你可以随时使用debug.getmetatable,这将返回与该对象相关联的元表。


您不必过早地使用pcall调用任何内容。观察:

pcall(function(...) return PossibleFunction(...) end, <insert arguments here>)

答案 1 :(得分:0)

这种改进Nicol的答案的尝试仍然存在需要调用表的问题,但它告诉所提供的表是否实际上是可调用的。即使表是可调用的,如果在执行false元方法期间出现错误,__call()也将返回local result = {pcall(PossibleFunction, ...)} if not result[1] then if result[2]:match"^attempt to call" then error("The provided value is not callable.") else -- Table was callable but failed. Just hand on the error. error(result[2]) end end -- Do something with the results: for i = 2, #result do print(result[i]) end

JNI- java.lang.UnsatisfiedLinkError: Native error: method not found

以这种方式检查错误消息然而感觉不是很“干净”(如果使用的Lua解释器例如用本地化的错误消息修改了怎么办?)。

答案 2 :(得分:-1)

function iscallable(x)
    if type(x) == 'function' then
        return true
    elseif type(x) == 'table' then
        -- It would be elegant and quick to say
        -- `return iscallable(debug.getmetatable(x))`
        -- but that is actually not quite correct
        -- (at least in my experiments), since it appears
        -- that the `__call` metamethod must be a *function* value
        -- (and not some table that has been made callable)
        local mt = debug.getmetatable(x)
        return type(mt) == "table" and type(mt.__call) == "function"
    else
        return false
    end
end

return iscallable

那你就可以做

> = iscallable(function() end)
true
> = iscallable({})
false
> = iscallable()
false
> = iscallable(nil)
false
> x = {}
> setmetatable(x, {__call=function() end})
> = iscallable(x)
true

如果您无权访问调试库,那么您可能会很难完全准确,因为您可能会弄乱元表。您可以使用pcall,但很难正确区分出错误。即使您按照此处的其他答案搜索特定的错误字符串,也可能是因为该函数内部的某些内容被称为不可调用,如果可以的话,该特定值也无法被调用。