【问题标题】:Can lua function references be used as table keys?lua 函数引用可以用作表键吗?
【发布时间】:2023-03-18 06:41:01
【问题描述】:

这里是 Lua 新手。我可以将函数引用作为键存储在 Lua 表中吗?类似的东西:

local fn = function() print('hello') end
local my_table = {}
my_table[fn] = 123

这似乎工作正常,但我不知道我是否可以依赖函数引用的唯一性。一旦超出范围,Lua 可以重用函数引用吗?这会产生任何问题还是由于某种原因被认为是一种不好的做法?

【问题讨论】:

    标签: function reference lua key lua-table


    【解决方案1】:

    是的。我在 lua 中遇到的最好的事情之一就是 anything as references 属性。

    您在表格中使用keys 的方式没有任何问题。

    来自Lua PiL

    Lua 中的表既不是值也不是变量;它们是对象。您可以将表视为动态分配的对象;您的程序仅操作对它们的引用(或指针)。幕后没有隐藏副本或创建新表。

    在您的示例中,您没有将任何参数传递给函数,因此基本上,在您的情况下,将函数作为程序中的引用是没有用的。另一方面,是这样的:

    fn1 = function(x) print(x) end
    fn2 = function(x) print("bar") end
    t[fn1] = "foo"
    t[fn2] = "foo"
    for i, v in pairs(t) do i(v) end
    

    确实有它的用途。

    一旦超出范围,Lua 是否可以重用函数引用?

    只要您的父表在范围内,就可以。由于表是创建和操作的,但不是复制的,所以你的函数引用不可能从表索引内存中被弃用。 我也会在实际尝试后编辑这个答案。

    这会产生任何问题还是由于某种原因被认为是一种不好的做法?

    这只是一种不好的做法,因为熟悉其他语言的用户,如Cpython 等,在阅读表格时往往会考虑数组。在你没有这些顾虑,程序会完美运行。

    不知道能否依赖函数引用的唯一性。

    为什么?

    【讨论】:

    • 感谢您的详细解答!非常感激!我怀疑函数引用的唯一性,因为在极少数情况下,两个函数具有相同的主体,Lua 解释器可能决定将其设为单个引用以节省内存,就像大多数语言中空对象和相同字符串的情况一样。也就是说,在大多数项目中不应出现具有相同主体的两个功能的情况。其他原因是 Lua 可以为其他函数使用相同的哈希码(通过打印函数或调用 tostring(fn) 看到的哈希码)。但正如你所澄清的,除非它被 gc'ed,否则这是不可能的。
    • 即使使用相同的正文,只要您为它们使用单​​独的names,它们被分配新的引用。
    • @BackinaFlash 通常不正确。 5.1 官方解释器确实如此;但不适用于 5.2。我相信这取决于个人实施。
    【解决方案2】:

    函数引用的唯一性取决于 Lua 版本。

    Lua 5.2 手册说:
    a function definition may not create a new value; it may reuse some previous value if there is no observable difference to the new function

    例子:

    -- 10 different function references on Lua 5.1
    -- The same function reference for Lua 5.2
    local j
    for i = 1, 10 do
       print(function() print(j) end)
    end
    
    -- 10 different function references for any Lua version
    for i = 1, 10 do
       print(function() print(i) end)
    end
    

    因此,规则是:创建不同的闭包以获取不同的引用。

    【讨论】:

    • 谢谢叶戈尔!这是一件很重要的事情。但是,我不希望我的项目中有两个具有相同主体的函数,所以这无关紧要。
    • 此外,如果我们在不同的范围内创建具有相同主体的两个函数,例如作为不同表中的值,那么它们确实会获得唯一的引用,这样就可以解决相同主体函数存在的任何小机会。
    【解决方案3】:

    您可以这样做,function 将保留在内存的同一位置,直到它被销毁(被垃圾收集器)。

    您可以尝试互动lua

    > fn = function() print('hello') end
    > print(fn)
    function: 0x9d058d0
    
    > fn2 = function() print('hello') end
    > print(fn2)
    function: 0x9d05ee8
    
    > fn2=fn
    > print(fn2)
    function: 0x9d058d0
    
    > print(function() print('hello') end)
    function: 0x9d068a8
    
    > print(function() print('hello') end)
    function: 0x9d06bf8
    

    请记住,如果fnlocal,则在超出范围时将被垃圾回收。在您的情况下,这应该不是问题,因为 my_table 在同一块中是 local。见Lua documentation on local variables

    【讨论】:

    • 在 luajit 中打印 nil?!
    【解决方案4】:

    这似乎工作正常,但我不知道我是否可以依赖函数引用的唯一性。

    每个function() end 语句都会创建一个新的闭包。一个函数的实际代码如果来自同一个构造函数,将被重用:

    for i=1,100 do
        t[function() print(i) end] = i -- this function body will be reused
    end
    

    但是每个闭包都是独一无二的,这对你的参考很重要。

    一旦超出范围,Lua 可以重用函数引用吗?

    Lua 不会收集fn,只要它被用作my_table 中的键。如果my_table 也超出范围,导致表和函数都被收集,那么 Lua 重用引用不会影响您。所以无论哪种方式,你都很好。

    【讨论】:

      猜你喜欢
      • 2015-06-10
      • 2021-09-06
      • 1970-01-01
      • 2014-08-07
      • 2013-05-26
      • 1970-01-01
      • 2012-05-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多