Lua中的全局变量不需要声明就可以使用。对于小程序十分方便,但是大型程序中 一处简单的笔误就可能造成难以发现的bug。

不过,这种性能可以改变。由于Lua将全局变量放在一个普通的table中,可以通过元表来改变其访问全局变量时的行为。

一种方法是简单地检测所有对全局table中不存在key的访问:

setmetatable(_G,{
__newindex = function(_, n)
error("attempt to write to undeclared variable " .. n ,)
end , --这里的逗号不能省,因为是在table构造式里哦
__index = function(_, n)
error("attempt to read undeclared variable " .. n, )
end , --这里的逗号不能省,因为是在table构造式里哦
}

执行这段代码后,所有对全局table中不存在的key访问都将引发一个错误:

print(a)        --> stdin:1: attempt to read undeclared variable a

但是该如何声明一个新的变量呢?

一种方法是使用rawset,可以绕过元表:

function declare(name ,initval)
rawset(_G,name ,initval or false) --这里的false确保 新变量不为 nil
end

另外一中更简单的方法就是只允许在主程序块中对全局变量进行赋值,那么当声明以下变量时:

a  =  

就只需检查此赋值是否在主程序块中。这可以使用debug库,调用debug.getinfo(2,"S")将返回一个table,

其中的字段what表示了调用元方法的函数是主程序块还是普通的Lua函数,或是C函数。

可以通过该函数将__newindex元方法重写:

__newindex = function(t,n,v)
local w = debug.getinfo(,"S").what
if w ~= "main" and w ~= "C" then --接收main和C代码的修改赋值
error("attempt to write to undeclared variable ".. n,)
end
rawset(t,n,v)
end

这个版本可以接收C代码的赋值,因为一般C代码都知道自己是做什么的。

为了测试一个变量是否存在,就不能简单地与nil 比较。因为如果它为nil ,访问就会抛出一个错误,这时同样可以使用rawget来绕过元方法:

if rawget(_G , var ) ==nil then
-- 'var' 没有声明
...
end

正如前面提到的,不允许全局变量具有nil 值,因为具有nil 的全局变量都会被自动认为是未声明的。

但要纠正这个问题并不难,只需引入一个辅助table用于保存已经声明变量的名称。

一旦调用了元方法,就检查该table,以确定变量是否已经声明过:

local declaredNames = {}
setmetatable( _G , {
__newindex = function( t , n, v)
if not declaredNames[n] then
local w = debug.getinfo(,"S").what
if w ~= "main" and w ~= "C" then
error("attempt to write to undeclared variable " .. n, )
end
declaredNames[n] = true
end
rawset(t , n ,v ) --完成实际的设置
end ,
__index = function (_, n)
if not declaredNames[n] then
error("attempt to read undeclared variable " .. n, )
else
return nil
end
end ,
}
)

此时,即使是下面的赋值也可以起到声明全局变量的作用:

x = nil

上述两中方法所导致的开销基本可以忽略不计;

第一种方法中,完全没有涉及到元方法的调用。

第二种方法,只有当程序访问一个为nil的变量时才会去调用元方法。

以上内容来自:《Lua程序设计第二版》和《Programming in Lua  third edition》

Chapter 14_2 全局变量声明的更多相关文章

  1. Python基础(六)_全局变量声明、可变参数、关键字参数

    1. global声明全局变量 #声明name这个变量为全局变量,只是写在函数里面 #写代码时,尽量不要用全局变量,会一直占用内存.       ------->{'name':'abc','s ...

  2. js中三种全局变量声明方法

    声明方式一: 使用var(关键字)+变量名(标识符)的方式在function外部声明,即为全局变量,否则在function声明的是局部变量.该方式即为显式声明详细如下: <script> ...

  3. C语言的傻瓜式随笔(二):全局变量、预编译、goto

    函数的作用:可以实现代码的重用. 函数只需要定义1次,那么函数中的代码就可以随意的调用.       -某不知出处的基本概念 学而时习之,如有误笔,请指正 一.goto跳转语句 goto在C语言的作用 ...

  4. 变量声明和定义及extern 转载

    在讨论全局变量之前我们先要明白几个基本的概念: 1. 编译单元(模块):    在IDE开发工具大行其道的今天,对于编译的一些概念很多人已经不再清楚了,很多程序员最怕的就是处理连接错误(LINK ER ...

  5. 剖析javascript全局变量和局部变量

    首先要记住: javascript是弱类型语言,它只有一种变量类型(var),为变量赋值时会自动判断类型并进行转换. 全局变量和局部变量如何声明? 全局变量声明: 第一种方式(函数外) var a; ...

  6. C/C++定义全局变量/常量几种方法的区别

    在讨论全局变量之前我们先要明白几个基本的概念: 1. 编译单元(模块):    在IDE开发工具大行其道的今天,对于编译的一些概念很多人已经不再清楚了,很多程序员最怕的就是处理连接错误(LINK ER ...

  7. JavaScript学习01 语言简介、基本使用和变量声明

    JavaScript语言简介.基本使用和变量声明 JavaScript是网景(Netscape)公司开发的一种基于客户端浏览器.面向对象.事件驱动式的网页脚本语言. JavaScript的前身叫Liv ...

  8. 用extern定义全局变量

    1.extern的作用 extern有两个作用,第一个,当它与"C"一起连用时,如: extern "C" void fun(int a, int b); 则告 ...

  9. 函数改变全局变量-JS

    切记,一定按三步走: 1. 全局变量声明 2. 函数声明 3. 函数调用 正确做法: var dataStr = null; function remoteCallback(data) { dataS ...

随机推荐

  1. 详解 UIView 的 Tint Color 属性

    在iOS 7后,UIView新增加了一个tintColor属性,这个属性定义了一个非默认的着色颜色值,其值的设置会影响到以视图为根视图的整个视图层次结构.它主要是应用到诸如app图标.导航栏.按钮等一 ...

  2. TODO:字节序的一些理解

    TODO:字节序的一些理解 本文是小编对字节序的片面理解,希望对你有帮助哈. 字节序,即字节在电脑中存放时的序列与输入(输出)时的序列是先到的在前还是后到的在前. 1.Little endian:将低 ...

  3. Another Array of Orz Pandas

    Another Array of Orz Pandas 题目链接:http://acm.xidian.edu.cn/problem.php?id=1187 线段树 线段树维护区间和以及区间内各个数平方 ...

  4. python向服务器发送邮件事例

    import osimport sysimport re __author__ = 'xiaoming' import requestststr = '<div>\n<ul>\ ...

  5. PHP微信支付开发之扫描支付(模式二)后如何回调

    其实在写这篇文章的时候感觉自己已经落伍了,不过笔者在百度上搜索"微信支付开发之扫描支付(模式二)后如何回调"寻找答案时,发现依旧有很多朋友没有解决这个问题,所以就把自己的解决思路分 ...

  6. Tomcat7性能调优

    open files 修改linux系统open files限制,通过ulimit –a可看到系统默认的一个进程最大打开文件数为1024,linux系统中一切皆为文件,包含socket连接,需将些值调 ...

  7. HDU 1040 As Easy As A+B(排序)

    As Easy As A+B Problem Description These days, I am thinking about a question, how can I get a probl ...

  8. Android UI方面的学习记录

    1,android:textAllCaps=“false” android5.0后有可能button的text显示全是大写,设置这个后才能正常显示小写 2,优化listview性能: 1,view重用 ...

  9. url地址数据转换成json数据格式

    var urlToJson = function(){ var ret = {}; window.location.search.substr(1).replace(/(\w+)=(\w+)/ig, ...

  10. 关闭Pycharm拼写检查(Mac)

    1.关闭拼写检查,preference-->Editor-->Inspections-->Spelling-->Typo,取消勾选 2.关闭代码风格检查,preference- ...