1

例如,我有一张桌子

table.insert( t, 1, function()
                        print ("rock");
                    end );

有没有办法从这个表中获取函数名。我知道我可以像键一样存储名称,但是如果我想保留数字索引并且还想知道函数名称怎么办?有什么办法吗?谢谢,提前。

4

4 回答 4

6

假设您有以下代码:

t = {}
x = 5
table.insert(t, 1, x)

t那么将是{[1] = 5}. “5”只是一个数字——它没有名字,并且与变量“x”无关;这是一个在 Lua 中,函数的处理方式与values
完全相同:

t = {}
x = function() print("test! :D") end
table.insert(t, 1, x)

x 的值不以任何方式、形状或形式与 x 相关联。如果要手动命名函数,可以通过将函数包装在表中来实现,例如:

t = {}
x = function() print("test! :D") end
table.insert(t, 1, {
    name = "MyFunctionName",
    func = x
})

这就是你将如何做到的!

...除非..

..你打破了规则!
当 Lua 被开发出来时,开发人员意识到函数的匿名性质会使生产性错误消息难以产生,如果不是不可能的话。
你会看到的最好的事情是:

stdin: some error!
  stdin: in function 'unknown'
  stdin: in function 'unknown'

所以,他们做到了,当 Lua 代码被解析时,它会记录一些调试信息,让生活更轻松。为了从 Lua 本身访问这些信息,提供了调试库
对这个库中的函数要非常小心。

使用此库时应小心。此处提供的功能应专门用于调试和类似任务,例如分析。请抵制将它们用作常用编程工具的诱惑:它们可能非常慢。此外,其中一些函数违反了一些关于 Lua代码的假设(例如,函数的本地变量不能从外部访问,或者用户数据元表不能被 Lua 代码更改),因此可能会危及其他安全代码。

要达到你想要的效果,你必须使用该debug.getinfo功能;一个例子:

x = function()
    print("test!")
    print(debug.getinfo(1, "n").name)
end
x() -- prints "test!" followed by "x"

不幸的是,直接在函数上运行的 debug.getinfo 形式不填充name参数 ( debug.getinfo(x, "n").name == nil),并且上面的版本要求您运行该函数。
似乎没有希望了!

...除非..

..你真的打破了规则。
debug.sethook功能允许您在某些事件中中断正在运行的 Lua 代码,甚至在这一切都发生时改变事情。这与coroutines相结合,可以让你做一些有趣的 hacky 事情。
这是一个实现debug.getfuncname

function debug.getfuncname(f)
    --[[If name found, returns
            name source line
        If name not found, returns
            nil  source line
        If error, returns
            nil  nil    error
    ]]
    if type(f) == "function" then
        local info = debug.getinfo(f, "S")
        if not info or not info.what then
            return nil, nil, "Invalid function"
        elseif info.what == "C" then
            -- cannot be called on C functions, as they would execute!
            return nil, nil, "C function"
        end
        --[[Deep magic, look away!]]
        local co = coroutine.create(f)
        local name, source, linedefined
        debug.sethook(co, function(event, line)
            local info = debug.getinfo(2, "Sn")
            name = info.namewhat ~= "" and info.name or nil
            source, linedefined = info.short_src, info.linedefined
            coroutine.yield() -- prevent function from executing code
        end, "c")
        coroutine.resume(co)
        return name, source, linedefined
    end
    return nil, nil, "Not a function"
end

示例用法:

function test()
    print("If this prints, stuff went really wrong!")
end

print("Name = ", debug.getfuncname(test))

这个功能不是很可靠——它有时有效,而其他时候无效。调试库非常敏感,所以这是意料之中的。

请注意,您永远不应该将它用于实际的发布代码!仅用于调试!
仍然可以接受的最极端情况是在已发布软件上记录错误,以帮助开发人员解决问题。任何重要的代码都不应该依赖于调试库中的函数。

祝你好运!

于 2011-12-20T15:49:59.660 回答
1

该函数没有任何名称。如果需要,可以将其分配给命名变量:

theFunction = t[1]
-- Call it:
theFunction()

如果您想要将命名函数存储到表中,请预先定义它并使用其名称来存储它:

theFunction = function()
                  print ("rock");
              end

table.insert(t, 1, theFunction)

如果这不是您的意思,请提供更多详细信息;例如,您希望如何访问该功能。你的问题有点模糊。

于 2011-12-20T11:41:19.613 回答
0

您可以将名称存储在单独的表中。

functions = {}
functionNames = {}

function addFunction(f, name)
  table.insert(functions, f)
  functionNames[name] = f
end

要获取函数,可以使用索引。一旦你有了这个函数,你可以从 function_names 中得到它的名字:

f = functions[3]
name = functionNames[f]

祝你好运!

于 2011-12-20T15:01:52.753 回答
0

事情是 table.insert 将表格视为一个序列,只有数字键。

如果您希望能够调用该函数,t.fun()则必须将表用作关联数组,因此使用字符串作为键。(顺便说一句,除了 nil 或 NaN 之外的任何类型都可以作为键)

t={}
t['MyFun']=function print'foo' end
t.myFun() -- uses syntactic sugar for string keys that are valid identifiers.

您可能还注意到函数是通过引用传递的。因此,所有函数实际上都是匿名的,并且只是作为某个键或变量的值存储。

于 2011-12-20T11:59:40.847 回答