zoukankan      html  css  js  c++  java
  • Lua环境

     Lua将其所有的全局变量保存在一个常规的table中,这个table被称为“环境”。它被保存在全局变量_G中。
        1. 全局变量声明:
        Lua中的全局变量不需要声明就可以使用。尽管很方便,但是一旦出现笔误就会造成难以发现的错误。我们可以通过给_G表加元表的方式来保护全局变量的读取和设置,这样就能降低这种笔误问题的发生几率了。见如下示例代码:

    复制代码
     1 --该table用于存储所有已经声明过的全局变量名
    2 local declaredNames = {}
    3 local mt = {
    4 __newindex = function(table,name,value)
    5 --先检查新的名字是否已经声明过,如果存在,这直接通过rawset函数设置即可。
    6 if not declaredNames[name] then
    7 --再检查本次操作是否是在主程序或者C代码中完成的,如果是,就继续设置,否则报错。
    8 local w = debug.getinfo(2,"S").what
    9 if w ~= "main" and w ~= "C" then
    10 error("attempt to write to undeclared variable " .. name)
    11 end
    12 --在实际设置之前,更新一下declaredNames表,下次再设置时就无需检查了。
    13 declaredNames[name] = true
    14 end
    15 print("Setting " .. name .. " to " .. value)
    16 rawset(table,name,value)
    17 end,
    18
    19 __index = function(_,name)
    20 if not declaredNames[name] then
    21 error("attempt to read undeclared variable " .. name)
    22 else
    23 return rawget(_,name)
    24 end
    25 end
    26 }
    27 setmetatable(_G,mt)
    28
    29 a = 11
    30 local kk = aa
    31
    32 --输出结果为:
    33 --[[
    34 Setting a to 11
    35 lua: d:/test.lua:21: attempt to read undeclared variable aa
    36 stack traceback:
    37 [C]: in function 'error'
    38 d:/test.lua:21: in function <d:/test.lua:19>
    39 d:/test.lua:30: in main chunk
    40 [C]: ?
    41 --]]
    复制代码


        2. 非全局的环境:
        全局环境存在一个刚性的问题,即它的修改将影响到程序的所有部分。Lua 5为此做了一些改进,新的特征可以支持每个函数拥有自己独立的全局环境,而由该函数创建的closure函数将继承该函数的全局变量表。这里我们可以通过setfenv函数来改变一个函数的环境,该函数接受两个参数,一个是函数名,另一个是新的环境table。第一个参数除了函数名本身,还可以指定为一个数字,以表示当前函数调用栈中的层数。数字1表示当前函数,2表示它的调用函数,以此类推。见如下代码:

    复制代码
     1 a = 1
    2 setfenv(1,{})
    3 print(a)
    4
    5 --输出结果为:
    6 --[[
    7 lua: d:/test.lua:3: attempt to call global 'print' (a nil value)
    8 stack traceback:
    9 d:/test.lua:3: in main chunk
    10 [C]: ?
    11 --]]
    复制代码

        为什么得到这样的结果呢?因为print和变量a一样,都是全局表中的字段,而新的全局表是空的,所以print调用将会报错。
        为了应对这一副作用,我们可以让原有的全局表_G作为新全局表的内部表,在访问已有全局变量时,可以直接转到_G中的字段,而对于新的全局字段,则保留在新的全局表中。这样即便是函数中的误修改,也不会影响到其他用到全局变量(_G)的地方。见如下代码:

    复制代码
     1 a = 1
    2 local newgt = {} --新环境表
    3 setmetatable(newgt,{__index = _G})
    4 setfenv(1,newgt)
    5 print(a) --输出1
    6
    7 a = 10
    8 print(a) --输出10
    9 print(_G.a) --输出1
    10 _G.a = 20
    11 print(a) --输出10
    复制代码

        最后给出的示例是函数环境变量的继承性。见如下代码:

    复制代码
     1 function factory()
    2 return function() return a end
    3 end
    4 a = 3
    5 f1 = factory()
    6 f2 = factory()
    7 print(f1()) --输出3
    8 print(f2()) --输出3
    9
    10 setfenv(f1,{a = 10})
    11 print(f1()) --输出10
    12 print(f2()) --输出3
    复制代码
     
    分类: Lua编程
  • 相关阅读:
    MySql清空所有表数据【慎用】
    积分墙已死?积分墙冲榜失效?请看看别人怎么玩转积分墙!
    [转]小心PHP的类定义顺序与继承的问题
    [转]PHP中替换换行符
    [转]php的public、protected、private三种访问控制模式的区别
    [转]Zend Studio中将tab转换为4个空格
    PHP预定义常量
    PHP Unit资料收集
    『Python』setup.py简介
    『计算机视觉』Mask-RCNN_项目文档翻译
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2572865.html
Copyright © 2011-2022 走看看