zoukankan      html  css  js  c++  java
  • Lua _G

    1.全局变量的原形

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

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

    而这个table的名字是:_G

    我们来看看代码:

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

    输出结果如下:

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

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

    怎么样,很简单吧。

    2.非全局的环境

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

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

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

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

    先看看以下代码:

    
    
    1.     -- 定义一个全局变量
    2.     gName "哎哟,很挫哦";
    3.    
    4.     -- 将当前全局环境重新设置为新的table
    5.     setfenv(1{});
    6.    
    7.     -- 输出值
    8.     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.    
    4.     -- 将当前全局环境重新设置为新的table
    5.     setfenv(1{g _G});
    6.    
    7.     -- 输出值
    8.     g.print(gName);
    9.    
    10.     -- 再次定义一个全局变量
    11.     gName "哎哟,有点错哦";
    12.    
    13.     -- 再次输出值
    14.     g.print(gName);
    15.    
    16.     -- 输出原来的值
    17.     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.    
    4.     -- 一个table,即将成为新的环境
    5.     local newG {};
    6.     setmetatable(newG{__index _G});
    7.    
    8.     -- 将当前全局环境重新设置为新的table
    9.     setfenv(1, newG);
    10.    
    11.     gName "别再哎哟了,很烦!";
    12.    
    13.     -- 输出值
    14.     print(gName);
    15.     print(_G.gName);
     

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

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

    输出结果如下

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

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

  • 相关阅读:
    git保存用户名密码的方式
    解决HP电脑播放视频,暂停后再次播放,前几秒钟会没有声音
    我们本想通过网络了解广袤的世界,而不是陷入推荐的漩涡
    cnblogs回来了
    mysql commit和事务
    服务器重启crontab服务
    linux多个命令行执行
    quick bi 配置即席查询sql 参数
    python 不定长参数
    python 和 mysql 的时间格式化
  • 原文地址:https://www.cnblogs.com/-colin/p/8275915.html
Copyright © 2011-2022 走看看