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. 【Time系列五】个性时钟与秒表升级版

    从昨天到现在,一直在研究这个看起来超级简单的时钟.界面非常简洁大方. 虽然是简单,可是这个对齐的问题还是把我整得一塌糊涂.谁叫作者不解释清楚的. 参考:http://bbs.fishc.com/thr ...

  2. 敏捷开发(八)- Scrum Sprint计划会议1

    本文主要是为了检测你对SCRUM Sprint 计划会议的了解和使用程度, 通过本文你可以检测一下     1.你们的SCRUM Sprint 计划会议的过程和步骤    2.会议的输出结果    S ...

  3. @property、@synthesize和dynamic的用法

    原文:  http://blog.csdn.net/hherima/article/details/8622948 @代表“Objective-C”的标志,证明您正在使用Objective-C语言 O ...

  4. 关于 div随网页居中问题

    可以先在外部设置个 宽高 小于浏览器的 div 内容再根据 最外层 定位 这个代码是 左右居中的 <div style=" width:300px; height:300px; mar ...

  5. C#中string的小结

    C#中的string类型明确定义为引用类型,但是使用时常常表现出数值型的特性.最典型的例子就是交换字符串. public static void stringexchange(string a, st ...

  6. centos6 搭建hdwiki

    前期准备:安装好Mysql+apache+PHP,测试apache能够解析index.php文件后就可以. 用户名 xiaohe 密码 123456 #### mysql安装好后: adduser w ...

  7. Python基础篇-day6

    本节简介: 1.模块1.1 时间模块1.2 random模块1.3 shutil模块1.4 shelve模块1.5 XML模块1.6 ConfigParser模块1.7 hashlib模块1.8 lo ...

  8. python_批量修改文件名

    1.在movies文件夹下面的所有文件前面都加上[可可可可] #coding:utf-8 import os movie_name = os.listdir('./movies') for temp ...

  9. UML类图几种关系总结

    在UML类图中,常见的有以下几种关系: 泛化(Generalization),  实现(Realization),关联(Association),聚合(Aggregation),组合(Composit ...

  10. ITest

    渗透测试入门 我很简单,请不要欺负我 网站综合渗透实验: 真的很简单: 你是会员吗: 2015中国网络安全大赛 一.代码执行: 同DZ漏洞全家桶中的"又见DZ,我能那你怎么办". ...