1.全局变量的原形

在Lua中,要声明全局变量很简单,那就是定义变量的时候,前面不要加上local。

这个神秘的全局变量,其实本质上也是一个table,它把我们创建的全局变量都保存到一个table里了。

而这个table的名字是:_G

我们来看看代码:


  1. -- 定义一个全局变量
  2. gName = "哎哟,很挫哦";
  3. -- 用三种方式输出变量的值
  4. print(gName);
  5. print(_G["gName"]);
  6. print(_G.gName);
 

输出结果如下:

[LUA-print] 哎哟,很挫哦
[LUA-print] 哎哟,很挫哦
[LUA-print] 哎哟,很挫哦

我们定义了一个全局变量gName,于是这个gName成为了_G的一个字段。

怎么样,很简单吧。

2.非全局的环境

对于全局变量,不管到了哪个地方,哪种语言,大家总是会告诫说:“不要滥用,后果自负”

也许是因为这样,所以Lua有了一种比较特殊的机制:非全局环境。

我称它为“不会造成全局影响的全局变量”。

3.改变函数的全局变量环境——setfenv函数

先看看以下代码:


  1. -- 定义一个全局变量
  2. gName = "哎哟,很挫哦";
  3. -- 将当前全局环境重新设置为新的table
  4. setfenv(1, {});
  5. -- 输出值
  6. 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保留起来。

如下代码:


  1. -- 定义一个全局变量
  2. gName = "哎哟,很挫哦";
  3. -- 将当前全局环境重新设置为新的table
  4. setfenv(1, {g = _G});
  5. -- 输出值
  6. g.print(gName);
  7. -- 再次定义一个全局变量
  8. gName = "哎哟,有点错哦";
  9. -- 再次输出值
  10. g.print(gName);
  11. -- 输出原来的值
  12. 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来解决这个问题,如下代码:


  1. -- 定义一个全局变量
  2. gName = "哎哟,很挫哦";
  3. -- 一个table,即将成为新的环境
  4. local newG = {};
  5. setmetatable(newG, {__index = _G});
  6. -- 将当前全局环境重新设置为新的table
  7. setfenv(1, newG);
  8. gName = "别再哎哟了,很烦!";
  9. -- 输出值
  10. print(gName);
  11. print(_G.gName);
 

我们给新的table设置一个元表,这个元表的__index元方法就是_G。

于是,当新的环境里找不到print字段时,就会去_G里寻找。

输出结果如下

[LUA-print] 别再哎哟了,很烦!
[LUA-print] 哎哟,很挫哦

第一次输出的是新环境里的gName值,第二次输出的是原来环境里的gName值,互不影响。

Lua _G的更多相关文章

  1. 怎么调试lua性能

    怎么调试lua性能 我们的游戏使用的是Cocos2dx-lua 3.9的项目,最近发现我们的游戏.运行比较缓慢.想做一次性能优化了.其实主要分为GPU.CPU的分别优化.GPU部分的优化.网上有很多优 ...

  2. Lua笔记

    闭包 示例一 function newCounter() return function() -- anonymous function i = i + return i end end c1 = n ...

  3. 15分钟学会Lua

    lua的很多语法跟matlab很像 最基本的赋值是一样的 循环和选择判断后面必须跟一个关键字:do和then ,, do ... end if - then - end table是lua的唯一一种数 ...

  4. lua中基类和“继承机制”

    基类:基类定义了所有对于派生类来说普通的属性和方法,派生类从基类继承所需的属性和方法,且在派生类中增加新的属性和方法. 继承:继承是C++语言的一种重要机制,它允许在已定义的类的基础上产生新类. lu ...

  5. Lua 基础

    Lua 5.3 的中文手册, http://cloudwu.github.io/lua53doc 在线浏览 --第一部分 -- 两个横线开始单行的注释 --[[ 加上两个[和]表示 多行的注释. -- ...

  6. Lua字符串库

    1. 基础字符串函数:    字符串库中有一些函数非常简单,如:    1). string.len(s) 返回字符串s的长度:    2). string.rep(s,n) 返回字符串s重复n次的结 ...

  7. lua 面向对象编程类机制实现

    lua no class It is a prototype based language. 在此语言中没有class关键字来创建类. 现代ES6, 已经添加class类. prototype bas ...

  8. lua 类支持属性不能被修改

    背景 lua是类是借助表的来实现的, 类被定义后, 在使用场景下, 不希望被修改.如果被修改, 则影响的类的原始定义, 影响所有使用类的地方. 例如: --- router.lua class fil ...

  9. Lua 与 Redis

    Lua 与 Redis 标签: Java与NoSQL 从 2.6版本 起, Redis 开始支持 Lua 脚本 让开发者自己扩展 Redis - 案例-实现访问频率限制: 实现访问者 $ip 在一定的 ...

随机推荐

  1. IDEA如何在一个项目空间下管理多个项目?

    用过Eclipse和IDEA编程工具都知道,Eclipse创建新项目时都是在同一项目空间下,而IDEA一个项目空间只能有一个项目,创建项目时会创建.idea文件. 所以每次创建完项目或者打开另一个项目 ...

  2. 【笔记】《Redis设计与实现》chapter13 客户端

    服务器为每个客户端建立相应的redis.h/redisClient结构,这个结构保存了客户端当前的状态信息 客户端的套接字描述符 客户端的名字 客户端的标志值 只想客户端正在使用的数据库的指针,以及该 ...

  3. 自动化kolla-ansible部署centos7.9+openstack-train-超融合高可用架构

    自动化kolla-ansible部署centos7.9+openstack-train-超融合高可用架构 欢迎加QQ群:1026880196 进行交流学习 环境说明: 1. 满足一台电脑一个网卡的环境 ...

  4. Salesforce学习之路(九)Org的命名空间

    1. 命名空间的适用场景 每个组件都是命名空间的一部分,如果Org中设置了命名空间前缀,那么需使用该命名空间访问组件.否则,使用默认命名空间访问组件,系统默认的命名空间为"c". ...

  5. python 闭包函数与装饰器

    1.什么是闭包函数 (1):什么是闭包函数: #内部函数包含对外部作用域而非全局作用域的引用, 简而言之, 闭包的特点就是内部函数引用了外部函数中的变量. 在Python中,支持将函数当做对象使用,也 ...

  6. src/众测篇:oracle注入过滤-- , + - * /,case when ,select,from,decode等函数如何证明是注入?

    (1)nullif: NULLIF:如果exp1和exp2相等则返回空(NULL),否则返回第一个值 真: 假: (2)nvl/nvl2 测试失败无法实现:)记录   (3)如果是oracle报错注入 ...

  7. 缓冲区溢出分析第10课:Winamp缓冲区溢出研究

    前言 Winamp是一款非常经典的音乐播放软件,它于上世纪九十年代后期问世.与现在音乐播放软件行业百家争鸣的情况不同,当时可以说Winamp就是听音乐的唯一选择了,相信那个时代的电脑玩家是深有体会的. ...

  8. 我为Dexposed续一秒——论ART上运行时 Method AOP实现

    转载于:http://weishu.me/2017/11/23/dexposed-on-art/ 两年前阿里开源了 Dexposed 项目,它能够在Dalvik上无侵入地实现运行时方法拦截,正如其介绍 ...

  9. Android持续优化 - 提高流畅度

    http://www.cnblogs.com/purediy/archive/2013/12/26/3492865.html

  10. 开源囧事4:你们这些卖代码的能不能留自己的QQ号?留我QQ号干嘛?

    缘起于开源项目 从 2017 年开始,陆陆续续写了一些开源项目放到开源网站里,都是一些实战项目,给大家练练手.有基础整合的demo,有 Spring Boot 博客项目,有 Spring Boot 商 ...