如何检测Lua脚本何时访问全局变量?

时间:2014-06-18 11:42:53

标签: lua

我开始使用C++/Lua代码库,这有点乱,当我在应用程序执行过程中转储_G的内容时,我确信有数百个变量只是在某处初始化,但不再在代码中的任何其他位置使用。为了清理它,我想设置一种机制,只要Lua访问全局变量就会记录。

这是我对如何实现这一点的想法 - 我想设置一个代理_G,它只能通过__index__newindex将所有读写访问传递给自己的副本原_G。但是这个简单的脚本不起作用,只输出:

C:\Programs\lua-5.1.5_Win32_bin\lua5.1: error in error handling

GProx = 
{
    vars = _G
}

setmetatable(GProx, {

    __index = function (t, name) 

        print("Read> " .. name)
        return t.vars[name]

    end,

    __newindex = function (t, name, val)

        print("Write> " .. name .. ' = ' .. val)
        t.vars[name] = val

    end

})

setfenv(0, GProx)

a = 1 --> Expected to print 'Write> a'
print(a) --> Expected to print 'Read> print', 'Read> a', and '1'

这是一个好方法还是有更好的方法来做到这一点? 如果这是一个有效的思路,那么我的代码片段有什么问题?

2 个答案:

答案 0 :(得分:3)

您可以直接在_G表格上设置元表,如PIL section 14.2中所述,所以您非常接近。网上还有一些现有的Lua模块可以做到这一点(也许penlight包含一个)。

答案 1 :(得分:3)

请尝试使用此代码段,它将与读取和写入一起使用:

do
    -- Use local variables
    local old_G, new_G = _G, {}

    -- Copy values if you want to silence logging
    -- about already set fields (eg. predeclared globals).
    -- for k, v in pairs(old_G) do new_G[k] = v end

    setmetatable(new_G, {
        __index = function (t, key)
            print("Read> " .. tostring(key))
            return old_G[key]
        end,

        __newindex = function (t, key, val)
            print("Write> " .. tostring(key) .. ' = ' .. tostring(val))
            old_G[key] = val
        end,
    })

    -- Set it at level 1 (top-level function)
    setfenv(1, new_G)
end

以下是这些变化的概述:

  • 块用于对旧_G进行本地引用。在您提议的实现中,如果设置了名为vars的全局变量,它将覆盖GProx.vars并中断代理。
  • keyval应在打印前通过tostring,因为大多数值(即表格)都不会隐式转换为字符串。
  • 设置1级别的环境通常就足够了,不会破坏Lua的内部工作。