解决滥用lua全局变量
在开发过程中发现有滥用lua全局变量的情况,原因是Lua的全局变量不用显示声明就能使用,(比如:Util = LuaFramework.Util )
解决问题:
1.避免全局变量,不显式声明就使用的情况,即,常用模块的全局变量,只能在主模块进行显式声明后才能使用,在项目别的位置使用或定义未经声明的全局变量,则抛出错误。
2.怎么避免重定义,从而覆盖了某全局变量的情况?
比如:(Util = LuaFramework.LogUtil),也不会影响_G("Util")原有的定义。
过程:在<Lua程序设计 第2版(中文版)>书中【14.2全局变量声明】和【14.3非全局环境】中已经对以上问题进行了探讨,具体的内容大家可以详细看看。
解决方案:
对于问题1:
引用strict.lua ,他实现了对全局变量的检查,只允许全局变量先声明再使用。
该代码的原理:
1.设置_G的metatable来运行时检测(肯定不能静态检测),当我们对_G表进行更新或者赋值是会触发__newindex 和 __index 元方法,
我们在这里进行约束:如果该变量从未显式的声明过,则抛出"assign to undeclared variable" 和 "variable n is not declared" 错误。
2.如何判断某全局变量是否声明过:debug.getinfo是调试Lua程序时一个很重要很常见的函数,主要用于获取函数调用的基本信息。
这个函数的难点在于各个参数的含义。
具体用法,直接百度就可以了。这里用getinfo(2,"s")获取 fills in the fieldssource,linedefined,lastlinedefined,what, andshort_src;(source)strict.lua定义__declared = {} 存放已经声明过的变量,
首先判断该变量是否存在__declared,如果不在再判断linedefined (函数定义的起始行号)是否大于0.,如果大于0则表示该变量未声明,反之则将该变量存入__declared 表.
对于问题2:
使用setfenv(f,table):设置一个函数的环境,关于具体的用法可以百度.
注意:
1.一旦改变了环境,所有的全局访问就都会使用新的table。如果新table是空的,
那么就会丢失所有的全局变量,包括_G.所有应该先将一些有用的值录入其中
2.使用继承组装新环境a = 1local newget = {}setmetatable(newgt,{__index = _G})setfenv(1,newgt)这段代码,
新环境从原环境中继承了print和a,然而,任何赋值都发生在新的table中。若误改了一个全局变量也没什么,仍然能通过_G来修改全局变量.由于函数继承了创建其函数的环境.所以一个程序块若改变了它自己的环境,
那么后续由它创建的函数都将共享这个新环境。
修改思路:
1.启动游戏,默认进行_G的沙盒环境。
2.自定义每个子游戏的沙盒环境.Env_Game1.Init(--组安新环境)
3.当子游戏模块载入成功后,触发回调Callback()调用setfenv(0,Env_Game1.GetEnv()):参数0,代表将当前环境切换为指定环境
4.从子游戏退出至大厅时,切换沙盒环境为_G