在lua中获取函数的参数名称

时间:2012-05-05 02:25:26

标签: lua

调用像

这样的lua函数时

PrintMe(MyVariableName)

我希望能够实际打印“MyVariableName”而不是它的价值(好吧,出于演示目的)。

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

例如,

MyVariable = 4
PrintVariable(MyVariable)

将打印“MyVariable为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显然是最方便的。

6 个答案:

答案 0 :(得分:4)

你不能说PrintVariable(MyVariable),因为Lua无法确定哪个变量(如果有的话;可以使用常量)用于将参数传递给你的函数。但是,您可以PrintVariable('MyVariable')然后使用调试API在调用者范围内查找具有该名称的局部变量:

function PrintVariable(name)
  -- default to showing the global with that name, if any
  local value = _G[name]

  -- see if we can find a local in the caller's scope with that name
  for i=1,math.huge do
    local localname, localvalue = debug.getlocal(2,i,1)
    if not localname then
      break -- no more locals to check
    elseif localname == name then
      value = localvalue
    end
  end

  if value then
    print(string.format("%s = %s", name, tostring(value)))
  else
    print(string.format("No variable named '%s' found.", name))
  end
end

现在你可以说:

PrintVariable('MyVariable')

虽然在这种情况下会打印“MyVariable = 4”。


不是,如果确实想要在没有引号的情况下执行此操作,您可以检查调用者的本地人是否有提供值的变量,但是如果有的话,偶尔会给你错误的变量名称是调用者范围内的多个变量,具有给定值。话虽如此,这就是你如何做到的:

function PrintVariable(value)
  local name

  -- see if we can find a local in the caller's scope with the given value
  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 we couldn't find a local, check globals
  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("No variable found for the value '%s'.", tostring(value)))
  end
end

现在你可以说PrintVariable(MyVariable),但是如果调用者范围内的另一个变量恰好是值4,并且它发生在MyVariable之前,那么它就是 < / em>将要打印的变量名称。

答案 1 :(得分:0)

我有个坏消息,我的朋友。您可以访问函数顶部显示的函数参数名称,但是不存在准确访问它们在调用函数中命名的数据。请参阅以下内容:

function PrintVariable(VariableToPrint)
  --we can use debug.getinfo() to determine the name 'VariableToPrint'
  --we cannot determine the name 'MyVariable' without some really convoluted stuff (see comment by VBRonPaulFan on his own answer)
  print(VariableToPrint);
end

MyVariable = 4
PrintVariable(MyVariable)

为了说明这一点,想象一下我们是否做过:

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

PrintVariable(MyVariable)

现在如果你是Lua,你会在元数据中将什么名称附加到最终传递给函数的变量?是的,您可以使用debug.getint()查找传入的变量,然后您可以找到多个引用。 还要考虑:

PrintVariable("StringLiteral")

你会称那个变量为什么?它有一个值但没有名字。

答案 2 :(得分:0)

你可以使用调试库做这样的事情...这样的事情就像你正在寻找的那样:

function a_func(arg1, asdf)
    -- if this function doesn't use an argument... it shows up as (*temporary) in 
    -- calls to debug.getlocal() because they aren't used...
    if arg1 == "10" then end
    if asdf == 99 then end
    -- does stuff with arg1 and asdf?
end

-- just a function to dump variables in a user-readable format
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()
    -- passing 2 to to debug.getinfo means 'give me info on the function that spawned 
    -- this call to this function'. level 1 is the C function that called the hook.
    local info = debug.getinfo(2)
    if info ~= nil and info.what == "Lua" then
        local i, variables = 1, {""}
        -- now run through all the local variables at this level of the lua stack
        while true do
            local name, value = debug.getlocal(2, i)
            if name == nil then
                break
            end
            -- this just skips unused variables
            if name ~= "(*temporary)" then
                variables[tostring(name)] = value
            end
            i = i + 1
        end
            -- this is what dumps info about a function thats been called
        print((info.name or "unknown").. "(".. myUnpack(variables).. ")")
    end
end

-- tell the debug library to call lua function 'hook 'every time a function call
-- is made...
debug.sethook(hook, "c")

-- call a function to try it out...
a_func("some string", 2012)

这导致输出:

a_func(asdf=2012, arg1=some string)

你可以做更好的事情,但这基本上涵盖了如何做你所要求的。

答案 3 :(得分:0)

您可以使用此表单:

local parms = { "MyVariable" }

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

local MyVariable = "bar"

PrintVariable{MyVariable}

给出了:

MyVariable: bar

这不是通用的,但很简单。您可以通过这种方式避免调试库和loadstring。如果您的编辑器有任何优点,您可以编写宏来执行此操作。

答案 4 :(得分:0)

另一种可能的解决方案是自己添加这个设施。 Lua C API和源代码非常简单且可扩展。

我/我们不知道您的项目/工作的上下文,但如果您正在制作/嵌入您自己的Lua构建,您可以扩展debug库以实现此目的。

Lua通过引用传递了它的值,但是如果它们中包含字符串名称,则是未知的,如果容易访问则是如此。

在您的示例中,值声明与:

相同
_G["MyVariable"] = 4

因为它是全球性的。如果它被声明为local,那么就像此处所述的其他人一样,您可以通过debug.getlocal()枚举这些内容。但是在实际参考上下文的C语境中,它可能并不重要。

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

答案 5 :(得分:0)

这是一个相当古老的话题,我很抱歉让它重获新生。

根据我使用 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

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