Chapter 14_2 全局变量声明
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 全局变量声明的更多相关文章
- Python基础(六)_全局变量声明、可变参数、关键字参数
1. global声明全局变量 #声明name这个变量为全局变量,只是写在函数里面 #写代码时,尽量不要用全局变量,会一直占用内存. ------->{'name':'abc','s ...
- js中三种全局变量声明方法
声明方式一: 使用var(关键字)+变量名(标识符)的方式在function外部声明,即为全局变量,否则在function声明的是局部变量.该方式即为显式声明详细如下: <script> ...
- C语言的傻瓜式随笔(二):全局变量、预编译、goto
函数的作用:可以实现代码的重用. 函数只需要定义1次,那么函数中的代码就可以随意的调用. -某不知出处的基本概念 学而时习之,如有误笔,请指正 一.goto跳转语句 goto在C语言的作用 ...
- 变量声明和定义及extern 转载
在讨论全局变量之前我们先要明白几个基本的概念: 1. 编译单元(模块): 在IDE开发工具大行其道的今天,对于编译的一些概念很多人已经不再清楚了,很多程序员最怕的就是处理连接错误(LINK ER ...
- 剖析javascript全局变量和局部变量
首先要记住: javascript是弱类型语言,它只有一种变量类型(var),为变量赋值时会自动判断类型并进行转换. 全局变量和局部变量如何声明? 全局变量声明: 第一种方式(函数外) var a; ...
- C/C++定义全局变量/常量几种方法的区别
在讨论全局变量之前我们先要明白几个基本的概念: 1. 编译单元(模块): 在IDE开发工具大行其道的今天,对于编译的一些概念很多人已经不再清楚了,很多程序员最怕的就是处理连接错误(LINK ER ...
- JavaScript学习01 语言简介、基本使用和变量声明
JavaScript语言简介.基本使用和变量声明 JavaScript是网景(Netscape)公司开发的一种基于客户端浏览器.面向对象.事件驱动式的网页脚本语言. JavaScript的前身叫Liv ...
- 用extern定义全局变量
1.extern的作用 extern有两个作用,第一个,当它与"C"一起连用时,如: extern "C" void fun(int a, int b); 则告 ...
- 函数改变全局变量-JS
切记,一定按三步走: 1. 全局变量声明 2. 函数声明 3. 函数调用 正确做法: var dataStr = null; function remoteCallback(data) { dataS ...
随机推荐
- 使用 Python Mock 类进行单元测试
数据类型.模型或节点——这些都只是mock对象可承担的角色.但mock在单元测试中扮演一个什么角色呢? 有时,你需要为单元测试的初始设置准备一些“其他”的代码资源.但这些资源兴许会不可用,不稳定,或者 ...
- css3 box-reflect 倒影效果
语法: box-reflect:包括3个值. 1. direction 定义方向,取值包括 above . below . left . right. above: 指定倒影在对象的上边 below: ...
- OllyDBG V1.10聆风听雨汉化版
软件名称:OllyDBG V1.10聆风听雨汉化版 软件语言: 简体中文 授权方式: 免费软件 运行环境: Win 32位/64位 软件大小: 3.84MB 图片预览: 软件简介: Ollydbg2. ...
- 自定义实现IEnumerable
Demo: http://files.cnblogs.com/files/georgeHeaven/Demo.IEnumerable.rar 一.使用场景 在开发过程中,经常需要使用foreach来循 ...
- CodeForces 672D Robin Hood
思维. 当$k$趋向于正无穷时,答案会呈现出两种情况,不是$0$就是$1$.我们可以先判断掉答案为$1$和$0$的情况,剩下的情况都需要计算. 需要计算的就是,将最小的几个数总共加$k$次,最小值最大 ...
- ASP.NET网站怎么发布 Web项目程序怎么发布部署(暂时收藏)
Web程序如何发布部署呢.网站项目做好了,需要发布出来,提交给客户,装上服务器.那怎么在ASP.NET开发环境中将网站程序发布出来呢 ^_^ 工具/原料 Visual Studio 2010 ( ...
- sql优化--in和exists效率
系统要求进行SQL优化,对效率比较低的SQL进行优化,使其运行效率更高,其中要求对SQL中的部分in/not in修改为exists/not exists 修改方法如下: in的SQL语句 SELEC ...
- reposync 同步yum仓库
reposync 同步远程yum仓库到本地 OPTIONS -h, --help 显示帮助 -c CONFIG, --config=CONFIG ...
- C#中XmlSerializer的内存占用问题
被XmlSerializer掉坑里了,爬了一晚上才出来. 本来实现一个功能,从数据库中查出一堆数据(比较多,几十万,不过,是分批查出来的),查出来的数据包含了一个XML字符串,代码中对其进行序列化,一 ...
- Java的关键字和标识符
1.关键字 Java中共有52个关键字,其中有两个保留字,虽然查到百度百科上说是50个,但是事实确实是有52个(47+3+2). 1.1保留字 Java语言的的保留字是指在Java中商务预留的关键字 ...