# 从架构层面杜绝lua中使用未定义的变量

标签(空格分隔): lua

---

lua中有一个很坑的地方:
1.就是如果一个变量拼写错误,会自动的认为你定义了一个值为nil的全局变量.
2.如果在function中定义一个局部变量,忘记了local,则会默认为是定义成为了一个全局变量.

为了防止这种问题,我今天想到一个解决方案.
可以达到以下效果:
1.在function中使用一个未定义的变量时则报错.
2.在function中定义全局变量则报错,即全局变量中能够在全局空间中定义.

具体做法如下:
在代码初始化的时候,重写_G的__newindex,这个是在往_G中加新东西的时候会调用的,即定义全局变量的时候会调用.
首先我们用一个table来记录定义了那些全局变量,这样做的目的是,我们之后可以在使用全局变量的时候判断时候已经定义了该全局变量.所以我们还应该重写__index,这个__index是在使用表中的内容会调用的.
所以有了如下代码:
```
local tbDefineValue = {}

setmetatable(_G, {
__index = function(tb, key)
if not tbDefineValue[key] then
error(string.format("找不到全局变量:%s", key))
return nil
end
rawget(tab, key)
end,
_newindex = function(tb, key, value)
tbDefineValue[key] = true
rawset(tb, key, value)
end
}

)
```
我们把这段代码放到一个全局空间的最先require的文件里面,做初始化.
这样之后我们每定义一个全局对象都会记录.
另外,很关键的一点是:这个代码会在初始化的调用.所以之后定义的全局变量会记录,使用全局变量会检查时候有该全局变量,如果有就返回,否则报错;

然后在程序运行过程中,我们需要有一个init函数来处理.
在运行过程中,我们需要禁止创建全局变量,只能够改变现有全局变量的值或者使用现有的全局变量.
所以我们需要禁止_G的__newindex的时候去增加全局变量.
所以我们有一个```init()```函数,用于设置_G只读.
代码如下:
```
function init()
setmetatable(_G, {
__newindex = function(tb, key, value)
do return end
-- tbDefineValue[key] = true
-- rawset(tb, key, value)
end,
})
end
```
大功告成.
以下是测试用例.
```
local tbDefineValue = {}
setmetatable(_G, {
__index = function(tb, key)
if not tbDefineValue[key] then
error(string.format("can not find global:%s", key))
return nil
end
rawget(tab, key)
end,
_newindex = function(tb, key, value)
tbDefineValue[key] = true
rawset(tb, key, value)
end
}
)

function disableWrite_G()
setmetatable(_G, {
__newindex = function(tb, key, value)
error(string.format("can not define global value:%s in local space", key))
do return end
end,
})
end

c = 12
print(c)

function test2()
d = 12
c = 13
end

function test3()
print(c)
if a == 12 then
print(123)
end
end

function start()
disableWrite_G()
test2()
test3()
end

start()
```
输出结果是
```
D:\Binaries-LuaDist-batteries-0.9.8-Windows-x86\bin\lua.exe: .\test.lua:20: can not define global value锛歞 in local space
stack traceback:
[C]: in function 'error'
.\test.lua:20: in function <.\test.lua:19>
.\test.lua:30: in function 'test2'
.\test.lua:43: in function 'start'
.\test.lua:47: in main chunk
[C]: ?

```

从架构层面杜绝lua中使用未定义的变量的更多相关文章

  1. js 温故而知新 用typeof 来判断一个未定义的变量

    一直以为,如果你使用一个未定义的变量,肯定会报错.甚至根本不可能有这种场景. 但仔细想想还是有的,譬如你要判断全局是否存在$变量.或者要为全局暴漏一个全局变量之前,先判断是否有这个变量. typeof ...

  2. 五十九、SAP中常用预定义系统变量

    一.SAP中常用预定义系统变量 内容如下: 二.系统变量定义在结构SYST里,我们打开SE38 三.在代码编辑器输入SYST变量 四.双击SYST,来到这个系统结构,里面有很多系统变量 五.我们随便写 ...

  3. 关于c调用lua 对‘luaL_newstate()’未定义的引用的问题解决办法

    #include <string.h>#include "lua.h"#include "lauxlib.h"#include "lual ...

  4. 情景剧:C/C++中的未定义行为(undefined behavior)

    写在前面 本文尝试以情景剧的方式,轻松.直观地解释C/C++中未定义行为(undefined behavior)的概念.设计动机.优缺点等内容1,希望读者能够通过阅读本文,对undefined beh ...

  5. C++中的"未定义的行为"

    2.1 位运算 位运算的运算对象是整数类型的,并且把运算对象看成是一个二进制位的集合.运算对象可以是带符号也可以是无符号.如果是带符号且值为负,那么位运算如何处理运算对象的符号位依赖于机器.而且此时的 ...

  6. js在函数中未定义的变量的处理

    <html> <head> <script type="text/javascript"> var z=1; function abc(){ x ...

  7. WPF/UWP 的 Grid 布局竟然有 Bug,还不止一个!了解 Grid 中那些未定义的布局规则

    只要你用 XAML 写代码,我敢打赌你一定用各种方式使(nuè)用(dài)过 Grid.不知你有没有在此过程中看到过 Grid 那些匪夷所思的布局结果呢? 本文将带你来看看 Grid 布局中的 Bu ...

  8. strcasecmp在VS2010中提示未定义标识符

    分析: strcasecmp(*,*)是用来比较字符串,定义在string.h头文件中,但是在windows下即使添加string.h头文件,依然会报错. 解决: 添加 #if defined(_MS ...

  9. javascript中的未定义和未声明

    我们在项目中,经常会定义一些变量(很多时候,定义过多的全局变量),当我们调用这些变量的时候,就会发生各种各样的突发状况. 看一个示例: var a; typeof a; typeof b; 很简单的一 ...

随机推荐

  1. 我要好offer之 C++大总结

    0. Google C++编程规范 英文版:http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml 中文版:http://zh-g ...

  2. 【CF1020A】New Building for SIS(签到)

    题意: 有n栋楼,从一栋楼某个地方,到大另一栋楼的某个地方,每栋楼给了连接楼的天桥,每走一层或者穿个一栋楼花费一分钟,求出起点到大目的点最少花费的时间 n,h<=1e8,q<=1e4 思路 ...

  3. 防止点击asp.net的button按钮刷新页面(保留button的外观)

    原文发布时间为:2008-08-06 -- 来源于本人的百度文章 [由搬家工具导入] Button btn=new Button(); 1、如果用 btn.Enabled=false;是可以防止刷新的 ...

  4. Day 19 函数之闭包、装饰器

    一.什么是装饰器 器即函数 装饰即修饰,意指为其他函数添加新功能 装饰器定义:本质就是函数,功能是为其他函数添加新功能 二.装饰器遵循的原则 1.不修改被装饰函数的源代码(开放封闭原则) 2.为被装饰 ...

  5. python 操作系统和进程

    一. 操作系统介绍 多道程序系统 多道程序设计技术       所谓多道程序设计技术,就是指允许多个程序同时进入内存并运行.即同时把多个程序放入内存,并允许它们交替在CPU中运行,它们共享系统中的各种 ...

  6. SpringMVC (<context:include-filter>和<context:exclude-filter>的使用)

    eg: 1.现在给定一个项目包的结构: com.yk.controller com.yk.service 2.在SpringMVC.XML有以下的配置: <!--扫描@controller注解- ...

  7. MyBatis的一级缓存和二级缓存

    一级缓存 是SqlSession级别的缓存,当使用了clearCache方法和,或者close方法的话,这个缓存失效,如果还有同样的查询,则还会发送一次查询 SqlSession session = ...

  8. Xcode搭建真机调试环境 图文实例

    本文介绍的Xcode搭建真机调试环境 图文实例,图文并茂,使我们学习起来更方便些,我们先来看内容. AD: 2013云计算架构师峰会超低价抢票中 Xcode搭建真机调试环境 是本文要介绍的内容,不多说 ...

  9. lfu-cache(需要O(1),所以挺难的)

    https://leetcode.com/problems/lfu-cache/ 很难,看了下面的参考: https://discuss.leetcode.com/topic/69137/java-o ...

  10. FreeBSD 8

    FreeBSD 8.0的安装过程和7.2区别不大.先在FreeBSD官方网站上下载安装镜像,我一般都下载DVD的ISO,也有人爱好下最小的安装包,然后通过FTP或HTTP方式从网上下载各个程序包. 这 ...