【问题标题】:Is it possible to figure out the return value of a function in lua? Or whether or not a function returns anything?是否可以在lua中找出函数的返回值?或者一个函数是否返回任何东西?
【发布时间】:2017-10-09 16:24:20
【问题描述】:

比如说我做了一个函数,它的目的是分析另一个作为参数提供的函数,并返回指定的函数是否会返回任何东西,如果是,它将返回什么值。

local function CheckFunctionReturn(func)
  --return whether func would return anything.
end
local function myFunc()
  return 123;
end
CheckFunctionReturn(myFunc);

我被这个困住了。也许调试库中有一个可以提供帮助的函数?我将不胜感激。

【问题讨论】:

  • 你可以得到string.dump(func)并分析这个函数返回值的字节码(搜索RETURN A B操作码,B=1表示没有返回值)。
  • 另见 lbci - webserver2.tecgraf.puc-rio.br/~lhf/ftp/lua/index.html#lbci的字节码检查器库
  • 但这似乎是XY problem...你真正想解决什么问题?
  • @mikebayko 这使它看起来像一个XY问题。你为什么要确定这一点?目的是什么?
  • @mikebayko:换一种说法吧。我想不出为什么我会需要甚至问这样一个函数问题。如果您不知道函数将返回什么,那么您可能不知道该函数将为您完成什么。因此,你没有理由调用它,因为你只是调用函数来让它们做某事。如果您希望能够捕获函数的返回值而不管有多少,那么您的问题是无用的(和the answer to that is easy)。那么为什么你需要知道呢?

标签: function lua return-value


【解决方案1】:

调试库中没有一个函数可以做到这一点。相反,您需要分析源代码或字节码以找出程序将执行的操作。有一些资源可用on the Lua wiki,上面也有其他人给出了很好的建议。

请注意,当给定任意输入时,任意函数是否会返回的问题是halting problem,并且在 1936 年 Alan Turing 证明在一般情况下是不可能解决的。但是,对于简单的函数和/或输入是可以解决的,所以如果您的具体情况足够简单,您也许可以做到。

【讨论】:

  • 简单示例:function() if condition() then return true end end 可以根据测试返回 0 或 1 个值。对于可变参数返回,例如function() if condition() return 23, foo() else return bar() end 结果甚至取决于一个或多个其他函数,这些函数也需要分析。如果(可能)无限循环、error/pcall、协程、外部 C 调用或一般外部影响(结果取决于天气/API 调用的结果/……),这将变得更加复杂并且不可能参与。
  • 感谢您的帮助,我非常感谢。
【解决方案2】:

这是一种快速而简单的解决方案(仅限 Lua 5.1,仅限 LE 架构),它可能在大多数情况下都有效,但并非总是如此。
它只回答“这个函数是否会返回一些值?”的问题

local function CheckFunctionReturn(func)
   -- returns true if func would return anything

   local d = string.dump(func)
   assert(d:sub(1,5) == "\27LuaQ") -- only Lua 5.1

   -- search for code before first "return" (0x0080001E)
   d = d:match"^.-\30%z\128%z"

   -- search for "return" with non-zero number of returned values
   for pos = #d % 4 + 1, #d, 4 do
      local b1, b2, b3, b4 = d:byte(pos, pos+3)
      local dword = b1 + 256 * (b2 + 256 * (b3 + 256 * b4))
      local OpCode, BC = dword % 64, math.floor(dword/16384)
      local B, C = math.floor(BC/512), BC % 512
      if OpCode == 30 and C == 0 and B ~= 1 then
         return true
      end
   end
   return false
end

print(CheckFunctionReturn(aFunctionToBeAnalyzed));

【讨论】:

  • 如果函数执行return SomeOtherFunction(params) 之类的操作,这会起作用吗?也就是说,如果它在其返回语句中使用尾调用?
  • @NicolBolas - 是的,具有多个(可变参数)值的“RETURN”操作码的存在被认为是“这个函数返回了一些东西”。出于某种奇怪的原因,Lua 总是生成与“RETURN VARARG”配对的“TAILCALL”。因此,不需要对“TAILCALL”操作码进行特殊处理。
  • 仅仅寻找返回指令只会将总是返回零长度列表的函数与有时可能返回非零长度列表的函数区分开来。
  • @TomBlodget - 正确。据我了解,OP 想要区分总是返回一些东西的函数和总是什么都不返回的函数(不执行这些函数)。
  • 也感谢您的帮助。我使用 Lua 5.1,所以你的解决方案肯定会帮助我至少找出一个函数是否会返回任何东西。
【解决方案3】:
local function CheckFunctionReturn(func)
    print(type(func()))
end

local function myFunc()
    return 123;
end

CheckFunctionReturn(myFunc);

我错过了什么吗?

【讨论】:

  • 对于这个特定的功能,这很好用,但我认为问题是关于一般的功能,而不仅仅是给出的例子。例如,要确定一个函数是否返回,您不能只运行该函数,因为如果它没有返回,您将永远得不到答案。 (你可以假设它不会返回,如果它需要超过 x 秒,但它可能只需要很长时间才能执行。)
【解决方案4】:

Lua 内置 debug API docs 说

返回钩子:当解释器从函数返回时调用。钩子在 Lua 离开函数之前被调用。没有标准方法可以访问函数返回的值。

【讨论】:

    猜你喜欢
    • 2016-11-10
    • 2018-08-09
    • 1970-01-01
    • 1970-01-01
    • 2014-10-23
    • 2019-09-14
    • 1970-01-01
    • 1970-01-01
    • 2022-12-03
    相关资源
    最近更新 更多