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)