Lua _G
1.全局变量的原形
在Lua中,要声明全局变量很简单,那就是定义变量的时候,前面不要加上local。
这个神秘的全局变量,其实本质上也是一个table,它把我们创建的全局变量都保存到一个table里了。
而这个table的名字是:_G
我们来看看代码:
- -- 定义一个全局变量
- gName = "哎哟,很挫哦";
- -- 用三种方式输出变量的值
- print(gName);
- print(_G["gName"]);
- print(_G.gName);
输出结果如下:
[LUA-print] 哎哟,很挫哦
[LUA-print] 哎哟,很挫哦
[LUA-print] 哎哟,很挫哦
我们定义了一个全局变量gName,于是这个gName成为了_G的一个字段。
怎么样,很简单吧。
2.非全局的环境
对于全局变量,不管到了哪个地方,哪种语言,大家总是会告诫说:“不要滥用,后果自负”
也许是因为这样,所以Lua有了一种比较特殊的机制:非全局环境。
我称它为“不会造成全局影响的全局变量”。
3.改变函数的全局变量环境——setfenv函数
先看看以下代码:
- -- 定义一个全局变量
- gName = "哎哟,很挫哦";
- -- 将当前全局环境重新设置为新的table
- setfenv(1, {});
- -- 输出值
- print(gName);
如果现在运行代码,输出结果将会是这样的:
[LUA-print] LUA ERROR: [string “src/main.lua”]:107: attempt to call global ‘print’ (a nil value)
为什么?很出乎意料的脸print函数都无法找到了?
这是因为我们已经把当前函数范围内的全局变量环境改变了,全局变量默认是保存在_G中的,而现在的全局变量是在一个新的table里。
目前这个table是空的,所以不存在任何全局变量。
setfenv函数就是用来改变某个函数范围里的全局环境的,通俗地说,就是把某个函数范围内的_G给弄没了。
setfenv函数两个参数分别代表:
1). 第一个参数,可以是即将要改变环境的函数,也可以是一个数字。数字1代表当前函数,数字2代表调用当前函数的函数,后面以此类推。
2).第二个参数,新的全局环境table。
4.保留原来的_G
现在连print函数都无法使用了,对于测试很不方便,我们可以做个小动作,把原来的_G保留起来。
如下代码:
- -- 定义一个全局变量
- gName = "哎哟,很挫哦";
- -- 将当前全局环境重新设置为新的table
- setfenv(1, {g = _G});
- -- 输出值
- g.print(gName);
- -- 再次定义一个全局变量
- gName = "哎哟,有点错哦";
- -- 再次输出值
- g.print(gName);
- -- 输出原来的值
- g.print(g.gName);
只要在定义新的环境时,把_G作为一个字段放到新的table里,就可以调用原来的全局变量了。
那么,输出结果如下:
[LUA-print] nil
[LUA-print] 哎哟,有点错哦
[LUA-print] 哎哟,很挫哦
三次调用g.print函数的输出结果都是不一样的:
a.第一次,此时刚刚重新设置了全局环境,这时候当前函数的全局变量只有一个,那就是g,所以gName的值是nil。
b.第二次,我们再一次对gName进行赋值,此时,已经在新的环境中了,所以接下来输出的gName值是存在的。
c.第三次,这次输出的是g.gName的值,通过g调用的gName值是原先的全局环境里的值,所以gName的值仍然是最初的“哎哟,很挫哦”。
其实,这有什么用呢?倒不如直接用局部变量好了。
确实,从这例子里看不出什么特别的地方。
书里对于知识的介绍都是由浅入深的,所以这里暂时也没有更深入的介绍,看到后面内容的时候,我再继续和大家分享。
5.使用__index元方法保留原来的_G
这里还有一个小技巧分享一下,刚刚举例保留_G,但是调用print等函数时还需要形如g.print的方式,有点碍事。
我们可以利用__index来解决这个问题,如下代码:
- -- 定义一个全局变量
- gName = "哎哟,很挫哦";
- -- 一个table,即将成为新的环境
- local newG = {};
- setmetatable(newG, {__index = _G});
- -- 将当前全局环境重新设置为新的table
- setfenv(1, newG);
- gName = "别再哎哟了,很烦!";
- -- 输出值
- print(gName);
- print(_G.gName);
我们给新的table设置一个元表,这个元表的__index元方法就是_G。
于是,当新的环境里找不到print字段时,就会去_G里寻找。
输出结果如下
[LUA-print] 别再哎哟了,很烦!
[LUA-print] 哎哟,很挫哦
第一次输出的是新环境里的gName值,第二次输出的是原来环境里的gName值,互不影响。
Lua _G的更多相关文章
- 怎么调试lua性能
怎么调试lua性能 我们的游戏使用的是Cocos2dx-lua 3.9的项目,最近发现我们的游戏.运行比较缓慢.想做一次性能优化了.其实主要分为GPU.CPU的分别优化.GPU部分的优化.网上有很多优 ...
- Lua笔记
闭包 示例一 function newCounter() return function() -- anonymous function i = i + return i end end c1 = n ...
- 15分钟学会Lua
lua的很多语法跟matlab很像 最基本的赋值是一样的 循环和选择判断后面必须跟一个关键字:do和then ,, do ... end if - then - end table是lua的唯一一种数 ...
- lua中基类和“继承机制”
基类:基类定义了所有对于派生类来说普通的属性和方法,派生类从基类继承所需的属性和方法,且在派生类中增加新的属性和方法. 继承:继承是C++语言的一种重要机制,它允许在已定义的类的基础上产生新类. lu ...
- Lua 基础
Lua 5.3 的中文手册, http://cloudwu.github.io/lua53doc 在线浏览 --第一部分 -- 两个横线开始单行的注释 --[[ 加上两个[和]表示 多行的注释. -- ...
- Lua字符串库
1. 基础字符串函数: 字符串库中有一些函数非常简单,如: 1). string.len(s) 返回字符串s的长度: 2). string.rep(s,n) 返回字符串s重复n次的结 ...
- lua 面向对象编程类机制实现
lua no class It is a prototype based language. 在此语言中没有class关键字来创建类. 现代ES6, 已经添加class类. prototype bas ...
- lua 类支持属性不能被修改
背景 lua是类是借助表的来实现的, 类被定义后, 在使用场景下, 不希望被修改.如果被修改, 则影响的类的原始定义, 影响所有使用类的地方. 例如: --- router.lua class fil ...
- Lua 与 Redis
Lua 与 Redis 标签: Java与NoSQL 从 2.6版本 起, Redis 开始支持 Lua 脚本 让开发者自己扩展 Redis - 案例-实现访问频率限制: 实现访问者 $ip 在一定的 ...
随机推荐
- Linux 用户和用户组管理(useradd userdel groupadd groupdel)
Linux 用户和用户组管理 Linux系统是一个多用户多任务的分时操作系统,任何一个要使用系统资源的用户,都必须首先向系统管理员申请一个账号,然后以这个账号的身份进入系统. Linux系统用户账户的 ...
- 翻译:《实用的Python编程》09_02_Third_party
目录 | 上一节 (9.1 包) | 下一节 (9.3 版本分发) 9.2 第三方模块 Python 拥有一个包含各种内置模块的大型库(自带电池(batteries included))(译注:&qu ...
- Java刷题-tree
一.分别按照二叉树先序,中序和后序打印所有的节点. 这道题就是书上的算法思想的实际使用,唯一需要特别注意到的是用递归的方式建树,还是比较巧妙的,因为一棵树的建立过程字符流是重复使用的,用递归的方式对根 ...
- 逆向初级-PE(五)
5.1.PE文件结构 1.什么是可执行文件? 可执行文件(executable fle)指的是可以由操作系统进行加载执行的文件. 可执行文件的格式: Windows平台: PE(Portable Ex ...
- 交换机之间的通信 VLAN和trunk
只有 PC0和PC2可通信,PC1和PC3可通信 将PC0和PC2加入同一个VLAN 将PC1和PC3加入同一个VLAN 将左边的交换机的Fa0/3口开启trunk模式即可(如下图)
- 2. robot framework 关键字,变量,循环
1 关键字的使用 RF的能力是由关键字提供的,所以,我们必须对RF的常用关键字有个了解,这样才能把RF用好. 最常用的关键字就在RF的标准库中 http://robotframework.org 其中 ...
- 【MySQL】若sql语句中order by指定了多个字段,则怎么排序?
举个例子吧:order by id desc,time desc先是按 id 降序排列 (优先)如果 id 字段 有些是一样的话 再按time 降序排列 (前提是满足id降序排列) order b ...
- Windows驱动派遣函数的学习
//派遣处理例程的介绍: //IPR简介: //IRP全称(I/O Request Package),即输入输出请求包.他是windows驱动的重要概念,用户模式下所有对驱动程序的I/O请求,全部由操 ...
- 使用BurpSuite抓取HTTPS网站的数据包
昨天面试,技术官问到了我如何使用BurpSuite抓取https网站的数据包,一时间没能回答上来(尴尬!).因为以前https网站的数据包我都是用Fiddler抓取的,Fiddlert自动帮我们配置好 ...
- POJ2239简单二分匹配
题意: 一周有7天,每天可以上12节课,现在给你每科课的上课时间,问你一周最多可以上几科课,一科课只要上一节就行了. 思路: 简单题目,直接二分就行了,好久没写二分匹配了,练习 ...