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 ...
随机推荐
- svn客户端的安装与中文版本语言库
首先在mac下下载svn或者其他软件请看另一篇博客链接:http://www.cnblogs.com/minyc/p/myc201606191543.html 另附svn常用命令操作详解:http:/ ...
- find用法积累
查找目录下的所有文件中是否含有某个字符串 find .|xargs grep -ri "IBM" 查找目录下的所有文件中是否含有某个字符串,并且只打印出文件名 find .|xar ...
- CentOS7 下安装telnet服务
今天搞了下 Centos 7 下面升级 openssl 和 openssh ,顺便装了下 telnet # 安装 telnet 避免 ssh 无法登录 yum -y install xinetd te ...
- Photoshop定义画笔选区为空的原因
定义画笔预设时,选择选区后需填充黑色,否则将出现选区为空的提示
- CodeForces 711D Directed Roads
计数,模拟. 首先观察一下给出的图的特点: $1.$一定存在环. $2.$可能存在多个环. 我们对每个环计算方案数,假设环$C$上包含$x$条边,那么把环$C$破坏掉的方案数有${2^x} - 2$种 ...
- R语言数据结构
5. 数据结构 5.1 数据结构简介 (1)向量 一个向量的所有元素必须有相同的类型(模式) (2)列表 列表可以非同质的 列表可按位置索引:lst[[2]] 抽取子列表:lst[c(2,5)] 列表 ...
- rte_mempool内存管理
DPDK以两种方式对外提供内存管理方法,一个是rte_mempool,主要用于网卡数据包的收发:一个是rte_malloc,主要为应用程序提供内存使用接口.本文讨论rte_mempool.rte_me ...
- centos 安装cacti监控
CentOS 6下Cacti搭建文档 安装依赖关系 yum -y install mysql-devel httpd php php-pdo php-snmp php-mysql lm_sensors ...
- JAVA读取本地配置文件实例
import java.io.InputStream; import java.util.Properties; public class FileProperties extends Propert ...
- SaltStack Job管理
Job基本管理 Jid: job id,格式为%Y%m%d%H%M%S%f 在master在下发指令消息时,会附带上产生的jid.minion在接收到指令开始执行时,会 在本地的cachedir(默认 ...