获取Lua函数的参数名称。

当我调用 Lua 函数时,比如:

PrintMe(MyVariableName)

我希望能够打印出 "MyVariableName",而不是它的值(至少在演示的时候是这样的)。

显然,我可以只传递字符串,但这需要额外的引号,并且我也想打印它的值。

例如,

MyVariable = 4
PrintVariable(MyVariable)

将打印出 "MyVariable is 4" 或者其他什么。

我不想重复变量的名称和值,比如

PrintVariable(MyVariable, "MyVariable")

因为这是不必要的重复。

Lua 能否处理这个问题呢?

我现在的做法是将变量名放在引号中传递,并使用 loadstring 来获取值,但我希望能够直接传递变量,而不需要额外的引号(我原以为 debug.getlocal 可以做到这一点,但它返回的是值而不是名称)。


下面是一个模拟示例:

function printme1(var, val)
    print(var.." = "..val)
end

function printme2(v)
    local r
    loadstring("r = "..v)() -- equivalent to r = a but must be used since v is a string representing a and not the object a
    print(v.." = "..tostring(r))
end

function printme3(v)
    -- unknown
end

a = 3

printme1("a", a)
printme2("a")
printme3(a)

在这种情况下,所有 3 个函数都应该打印相同的结果。printme3 显然是最方便的。

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

点赞
stackoverflow用户1368932
stackoverflow用户1368932

我有一个坏消息,朋友。你可以按照它们出现在函数顶部的方式访问函数参数名称,但是访问它们在调用函数中确切命名的数据不存在。看以下示例:

function PrintVariable(VariableToPrint)
  --我们可以使用debug.getinfo()来确定名称为'VariableToPrint'的变量
  --我们无法确定名称为'MyVariable'的变量,除非使用一些非常复杂的方法(参见VBRonPaulFan在他自己的答案中的评论)
  print(VariableToPrint);
end

MyVariable = 4
PrintVariable(MyVariable)

为说明这一点,想象一下如果我们这样做:

x = 4
MyVariable = x
MyOtherVariable = x
x = nil

PrintVariable(MyVariable)

现在,如果你是Lua,你会将哪个名称附加到传递给函数的变量的元数据中?是的,你可以使用debug.getint()向上遍历堆栈查找传入的变量,但你可能会发现几个引用。 还要考虑:

PrintVariable("StringLiteral")

你会如何称呼这个变量?它有一个值,但没有名称。

2012-05-05 04:01:14
stackoverflow用户1208078
stackoverflow用户1208078

你可以使用 debug 库来实现类似这样的事情... 下面的代码可以达到你想要的效果:

``` function a_func(arg1, asdf) -- 如果这个函数没有使用参数... 在调用 debug.getlocal() 的时候会显示 (*temporary),因为它们没有被使用... if arg1 == "10" then end if asdf == 99 then end -- 处理 arg1 和 asdf? end

-- 一个将变量以易读的格式输出的函数 function myUnpack(tbl) if type(tbl) ~= "table" then return "" end

local ret = ""
for k,v in pairs(tbl) do
    if tostring(v) ~= "" then
        ret = ret.. tostring(k).. "=".. tostring(v).. ", "
    end
end
return string.gsub(ret, ", $", "")

end

function hook() -- 把 2 传给 debug.getinfo 函数意味着“告诉我在调用这个函数时引发了这个调用的函数的信息”。1 级是调用 hook 的 C 函数。 local info = debug.getinfo(2) if info ~= nil and info.what == "Lua" then local i, variables = 1, {""} -- 现在遍历 Lua 栈中该层的所有局部变量 while true do local name, value = debug.getlocal(2, i) if name == nil then break end -- 这只是跳过未使用的变量 if name ~= "(*temporary)" then variables[tostring(name)] = value end i = i + 1 end -- 这是一个输出被调用的函数信息的函数 print((info.name or "unknown").. "(".. myUnpack(variables).. ")") end end

--

2012-05-05 04:40:58
stackoverflow用户501459
stackoverflow用户501459

你不能说PrintVariable(MyVariable),因为 Lua 没有办法确定哪个变量(如果有的话;可能使用了常量)被用作传递给函数的参数。但是,你可以说 PrintVariable('MyVariable'),然后使用 debug API 在调用者的作用域中查找具有该名称的本地变量:

function PrintVariable(name)
  --默认显示具有该名称的全局变量(如果有的话)
  local value = _G[name]

  --查找调用者作用域中是否有具有该名称的本地变量
  for i=1,math.huge do
    local localname, localvalue = debug.getlocal(2,i,1)
    if not localname then
      break --没有更多的本地变量需要检查
    elseif localname == name then
      value = localvalue
    end
  end

  if value then
    print(string.format("%s = %s", name, tostring(value)))
  else
    print(string.format("没有找到名为 '%s' 的变量。", name))
  end
end

现在,你可以这样说:

PrintVariable('MyVariable')

这种情况下将打印 "MyVariable = 4"。


不过,如果你真的想在不使用引号的情况下做到这一点,你可以检查调用者的本地变量,以找到一个具有指定值的变量名称,但是,如果在调用者的作用域中存在一个以上具有相同值的变量,那么有时会打印错误的变量名称。话虽如此,这里是如何做到这一点的:

function PrintVariable(value)
  local name

  --查找调用者的作用域中是否有具有指定值的本地变量
  for i=1,math.huge do
    local localname, localvalue = debug.getlocal(2,i,1)
    if not localname then
      break
    elseif localvalue == value then
      name = localname
    end
  end

  --如果找不到变量,则检查全局变量
  if not name then
    for globalname, globalvalue in pairs(_G) do
      if globalvalue == value then
        name = globalname
      end
    end
  end

  if name then
    print(string.format("%s = %s", name, tostring(value)))
  else
    print(string.format("没有找到值为 '%s' 的变量。", tostring(value)))
  end
end

现在,你可以说PrintVariable(MyVariable),但是,如果在调用者作用域中存在一个具有值 4 的变量,并且出现在 MyVariable 之前,那么将打印 那个 变量的名称。

2012-05-05 05:24:10
stackoverflow用户151501
stackoverflow用户151501

你可以使用以下这个形式:

local parms = { "MyVariable" }

local function PrintVariable(vars)
   print(parms[1]..": "..vars[1])
end

local MyVariable = "bar"

PrintVariable{MyVariable}

输出结果为:

MyVariable: bar

虽然这种方法不够通用,但确实很简单。通过这种方式,您可以避免使用 debug 库和 loadstring 函数。如果您的编辑器好的话,可以编写宏来执行此操作。

2012-05-05 12:47:30
stackoverflow用户1128881
stackoverflow用户1128881

另一种可能的解决方案是自己添加此功能。Lua C API和源码都非常简单且可扩展。

我们不知道你的项目/工作的上下文,但是如果你正在制作/嵌入自己的Lua构建,则可以通过在debug库中添加相应功能来扩展它。

Lua通过引用传递它的值,但是我们不清楚这些值中是否包含字符串名称,如果包含的话是否容易访问。

在你的示例中,该值声明与以下行相同:

_G["MyVariable"] = 4

因为它是全局的。如果它被声明为local,那么就像其他人在这里所说的那样,你可以通过debug.getlocal()枚举它们。但是,在实际引用上下文的C上下文中可能并不重要。

实现一个debug.getargumentinfo(...),将名称键值对扩展到参数表中。

2012-06-25 00:57:21
stackoverflow用户13025218
stackoverflow用户13025218

这是一个相当古老的话题,我很抱歉让它死灰复燃。

根据我的Lua经验,最接近OP所要求的东西就是这样的:

PrintVariable = {}
setmetatable(PrintVariable, {__index = function (self, k, v) return string.format('%s = %s', k, _G[k]) end})

VAR = 0
VAR2 = "Hello World"

print(PrintVariable.VAR, PrintVariable.VAR2)
-- Result: VAR = 0  VAR2 = Hello World

我不会赘述太多解释,因为代码相当易读,然而:

这里发生的事情很简单,你只需给PrintVariable变量设置一个元表,然后添加__index元方法,当表强制在其索引中搜索值时被调用,借助这种功能,你可以实现在示例中看到的效果。

参考:https://www.lua.org/manual/5.1/manual.html

我希望未来和新访客会发现这很有帮助。

2021-02-15 10:14:05