Lua 用一个名为environment 普通的表来保存所有的全局变量。(更精确的说,Lua
在一系列的environment 中保存他的“global”变量,但是我们有时候可以忽略这种多样
性)这种结果的优点之一是他简化了Lua 的内部实现,因为对于所有的全局变量没有必
要非要有不同的数据结构。另一个(主要的)优点是我们可以像其他表一样操作这个保存
全局变量的表。为了简化操作,Lua 将环境本身存储在一个全局变量_G 中,(_G._G 等
于_G)。例如,下面代码打印在当前环境中所有的全局变量的名字:
for n in pairs(_G) do print(n) end
这一章我们将讨论一些如何操纵环境的有用的技术。

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

--该table用于存储所有已经声明过的全局变量名
local declaredNames = {}
local mt = {
__newindex = function(table,name,value)
--先检查新的名字是否已经声明过,如果存在,这直接通过rawset函数设置即可。
if not declaredNames[name] then
--再检查本次操作是否是在主程序或者C代码中完成的,如果是,就继续设置,否则报错。
local w = debug.getinfo(,"S").what
if w ~= "main" and w ~= "C" then
error("attempt to write to undeclared variable " .. name)
end
--在实际设置之前,更新一下declaredNames表,下次再设置时就无需检查了。
declaredNames[name] = true
end
print("Setting " .. name .. " to " .. value)
rawset(table,name,value)
end, __index = function(_,name)
if not declaredNames[name] then
error("attempt to read undeclared variable " .. name)
else
return rawget(_,name)
end
end
}
setmetatable(_G,mt) a =
local kk = aa --输出结果为:
--[[
Setting a to 11
lua: d:/test.lua:21: attempt to read undeclared variable aa
stack traceback:
[C]: in function 'error'
d:/test.lua:21: in function <d:/test.lua:19>
d:/test.lua:30: in main chunk
[C]: ?
--]]

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

下面这段代码是企图应用setfenv 失败的例子:
a = 1 -- create a global variable
-- change current environment to a new empty table
setfenv(1, {})
print(a)
导致:
stdin:5: attempt to call global `print' (a nil value)
(你必须在单独的chunk 内运行这段代码,如果你在交互模式逐行运行他,每一行
都是一个不同的函数,调用setfenv 只会影响他自己的那一行。)一旦你改变了你的环境,
所有全局访问都使用这个新的表,如果她为空,你就丢失所有你的全局变量,甚至_G,
所以,你应该首先使用一些有用的值封装(populate)她,比如老的环境:

a = 1 -- create a global variable
-- change current environment
setfenv(1, {_G = _G})
_G.print(a) --> nil
_G.print(_G.a) --> 1

现在,当你访问"global" _G,他的值为旧的环境,其中你可以使用print 函数。

你也可以使用继承封装(populate)你的新的环境:
a = 1
local newgt = {} -- create new environment
setmetatable(newgt, {__index = _G})
setfenv(1, newgt) -- set it
print(a) --> 1
在这段代码新的环境从旧的环境中继承了print 和a;然而,任何赋值操作都对新表
进行,不用担心误操作修改了全局变量表。另外,你仍然可以通过_G 修改全局变量:

-- continuing previous code
a = 10
print(a) --> 10
print(_G.a) --> 1
_G.a = 20
print(_G.a) --> 20
当你创建一个新的函数时,他从创建他的函数继承了环境变量。所以,如果一个
chunk 改变了他自己的环境,这个chunk 所有在改变之后定义的函数都共享相同的环境,
都会受到影响。这对创建命名空间是非常有用的机制,我们下一章将会看到。

Programming in lua 环境的更多相关文章

  1. 【Lua学习笔记之:Lua环境搭建 Windows 不用 visual studio】

    Lua 环境搭建 Windows 不用 visual studio 系统环境:Win7 64bit 联系方式:yexiaopeng1992@126.com 前言: 最近需要学习Unity3d游戏中的热 ...

  2. lua 学习 (一 )Mac搭建lua环境和ide

    今天开始学习lua  首先是搭建环境 和 我的hello world 首先 交代一下我用的是 Mac 系统 所以在Mac上安装lua 环境很方便的 lua  Mointain Lion - Lua 5 ...

  3. VS2012+LUA环境搭建

    1 .启动VS2012,选择C++下的"win32"项目类型中的"Win2控制台应用程序" 2.工具——选项——项目和解决方案——VC++目录——可执行程序(C ...

  4. Nginx+lua环境搭建

    其实有点类似WampServer一站式安装包 wget http://openresty.org/download/ngx_openresty-1.7.10.1.tar.gz tar -zxvf ng ...

  5. VS2012配置Lua环境

    1.VS2012配置BabeLua插件 2.VS2012配置Lua 1.VS2012配置BabeLua插件 BabeLua插件简介: 安装方法: 关闭VS2012后直接安装BabeLua插件. 下载地 ...

  6. [Lua]Mac系统上安装Lua环境

    1.下载 Lua语言的官方网站 http://www.lua.org/ 下载最新版本的Lua环境 2.安装 解压下载包lua-5.3.1.tar.gz 打开终端Terminal 使用cd命令进入该目录 ...

  7. Mac 端配置 Lua 环境

    一.设计目的 Lua 是一种轻量级的脚本语言,其目的是为了嵌入到程序中,从而为程序提供灵活的扩展和定制功能. 二.特性 轻量级:编译后仅仅 100 余K,可以很方便的嵌入到程序中. 可扩展:Lua 提 ...

  8. 将C注册到lua环境中使用

    注册到lua的方式有两种,一种是lua解释器,如果支持动态链接,使用动态链接机制,将函数接口编译成动态链接库,然后将动态链接库放到lua的C路径(LUA_CPATH)中,然后在lua文件中直接使用 r ...

  9. ubuntu配置lua环境,并进行c与lua的相互调用

    1.安装lua环境 先查看一下apt可获取的lua版本 我们选择lua5.1版本进行安装 sudo apt install lua5.1 安装完之后测试一下是否安装成功,如果可以正常使用,则lua环境 ...

随机推荐

  1. css 多栏自适应布局

    在页面重构中,我们经常会需要实现多栏布局,例如n栏固定宽度 + m栏自适应宽度的组合,绝对布局+padding+百分比宽度是容易想到的比较暴力的解决方法,但是作为未来的"工程师", ...

  2. 一个react的完整项目展示

    和一些人的关系像平行线,一辈子相守相望,见于眼底藏于心间.就怕耐不住寂寞,冲动而成了相交线,在一个点尽情拥抱,从此便离得越来越远,再也不见.遇到这样的人,因为不想做恋人只能一时,所以才选择做朋友能一世 ...

  3. VS2010数据库连接问题

    我用SQL server 2008写了一个小表格,运行VS的前选择了 工具-连接数据库,然后选择了那个表格的名称.运行后出现如下错误提示,请问是哪里出了问题呢? 数据库连接版本有问题.在VS中把信用数 ...

  4. 20160409 javaweb 数据库连接池

    1.自己编写数据库连接池: package com.dzq.pool; import java.io.PrintWriter; import java.lang.reflect.InvocationH ...

  5. Android中log4j的运用

    网上一查关于android上面运用Log4j的运用,各种说需要添加多样的包的,照着log4j的官网教程看了下,给了个简单的输出到console上面的代码,似乎没什么用.看网上关于Log4j更多是在ja ...

  6. node.js 访问sql server的 node_modules “msnodesql"的安装编译方法

    http://stackoverflow.com/questions/19661811/unable-to-download-msnodesql-0-2-1-v0-10-x64-msi 首先要满足以下 ...

  7. c#打开txt文件并导入到textbox中

    OpenFileDialog openFileDialog = new OpenFileDialog(); openFileDialog.Title = " 请选择您要导入的模板文件:&qu ...

  8. java.lang.NoSuchMethodError: org.apache.neethi.Policy.normalize(Z)Lorg/apache/neethi/PolicyComponent

    记录一个org.apache.neethi包的异常 java.lang.NoSuchMethodError: org.apache.neethi.Policy.normalize(Z)Lorg/apa ...

  9. 《JavaScript高级程序设计》 阅读计划

    第一周       第1章 JavaScript简介   1 第2章 在Html中使用JavaScript 1 第3章 基本概念   3         第二周       第4章 变量.作用域和内存 ...

  10. jQuery EasyUI 提示框(Messager)用法

    jQuery EasyUI 提示框(Messager)不仅强大,而且也不用任何的HTML代码,只需要按照<jQuery EasyUI框架使用文档>包含必要文件后,在$(function() ...