Lua全局变量管理

时间:2024-01-28 20:17:22
 

  Lua全局变量不需要声明就可以使用。虽然这种特性在我们学习语言时很方便,但在项目中则可能因为一些手误漏掉local关键字而引起一些很难发现的BUG。现在的项目,为了方便热更新,大部分逻辑都采用lua来实现,所以在项目初期就对全局变量的进行了规范化的管理。

  首先,想要使用全局变量,必须先进行声明,才能使用。使用未声明的全局变量会报错,并定位到所在文件,所在行。具体实现方便如下,主要采用了lua的元表和元方法来实现。

 1 local _logerror = print
 2 
 3 local _global = {}
 4 
 5 local __global_mt = {
 6     __index = function(t, k)
 7         if not _global[k] then
 8             _logerror(debug.traceback("attempt to read an undeclared global variable :" .. k, 2))
 9         end
10 
11         return nil
12     end,
13 
14     __newindex = function(t, k, v)
15         if not _global[k] then
16             _logerror(debug.traceback("attempt to write an undeclared global variable : " .. k, 2))
17             return
18         end
19 
20         rawset(t, k, v)
21     end
22 }
23 
24 setmetatable(_G, __global_mt)

  测试代码如下:

1 require("global")
2 
3 test1 = 1
4 
5 print(test2)

  测试结果如下:

  [G] attempt to write an undeclared global variable : test1
  stack traceback:
  F:/workspace/LuaDemo/test.lua:3: in main chunk
  [C]: in ?
  [G] attempt to read an undeclared global variable :test2
  stack traceback:
  F:/workspace/LuaDemo/test.lua:5: in main chunk
  [C]: in ?
  nil

  要想使用全局变量必须使用使用特性的声明函数,这里主要是利用rawset,它可以绕过元方法:

local function _declare_global(k, v)
    if not rawget(_G, k) then
        rawset(_G, k, v or false)
    else
        _logerror(debug.traceback("variable was already declared: " .. k, 2))
        return nil
    end

    _global[k] = true
    return _G[k]
end

  为了项目的课阅读性,我们规定项目中所有全局变量命名必须是g_xxx的形式,增加了命名规则检测后,完整的global文件如下:

 1 local _logerror = print
 2 
 3 local _global = {}
 4 
 5 local __global_mt = {
 6     __index = function(t, k)
 7         if not _global[k] then
 8             _logerror(debug.traceback("attempt to read an undeclared global variable :" .. k, 2))
 9         end
10 
11         return nil
12     end,
13 
14     __newindex = function(t, k, v)
15         if not _global[k] then
16             _logerror(debug.traceback("attempt to write an undeclared global variable : " .. k, 2))
17             return
18         end
19 
20         rawset(t, k, v)
21     end
22 }
23 
24 setmetatable(_G, __global_mt)
25 
26 -- 全局变量命名规范(g_xxx)
27 local _naming_pattern = "g_"
28 
29 local function _declare_global(k, v)
30     if not rawget(_G, k) then
31         if k:sub(1, #_naming_pattern) ~= _naming_pattern then
32             _logerror("invalid naming: global variable name is g_xxx")
33         end
34 
35         rawset(_G, k, v or false)
36     else
37         _logerror(debug.traceback("variable was already declared: " .. k, 2))
38         return nil
39     end
40 
41     _global[k] = true
42     return _G[k]
43 end
44 
45 _declare_global("declare_G", _declare_global)

 

  所有全局变量声明格式(支持初始值为nil):

1 declare_G("g_test", 123)