因为_ENV是一个普通的变量,我们可以像其他变量一样去对它进行赋值和访问。

_ENV = nil

上面的赋值操作,将会使得在它之后的代码块不能直接访问全局变量。不过,对控制你的代码所使用的变量有用处。

local print , sin = pirnt , math.sin
_ENV = nil
print() --> 13
print(sin()) --> 0.42016703682664
print(math.cos()) -- error 访问全局变量都会引发错误

我们可以明确地用_ENV来绕过局部变量的声明。

a =                -- global
local a =
print(a) --> 12 (local)
print(_ENV.a) --> 13 (global)

一个主要用途是用它去改变一块代码的环境。一旦你改变了环境,所有的全局访问都会使用这个新的表:

_ENV = {}      --把当前环境清空
a = -- 在_ENV里创建一个域
print(a) --> stdin:4 attempt to call global 'print' (a nil value )

可以看到,在调用print的时候提示为nil。说明清空的_ENV里没有了print这样的全局变量。

因此,要做的应该是通过老的_G 把它移植过来。

a =   --create a global variable
_ENV = {g = _G }   --用旧的_G去改变新环境
a = --在新的_ENV 中创建 a
g.print(a) --> 1
g.print(g.a) --> 15 ,通过g可以在任何地方使用print函数,也可以用_G替代g

在Lua中,_G就是一个普通的名字。只有当Lua在创建一个原始全局表和把它赋为全局变量_G时,它才有了特殊的状态。

Lua其实不关心这个变量的值。但是每当我们要涉及到全局变量时,习惯上都是用它。

另一个要使用你的新环境的方法是用继承。

a  =
local newgt = {} --create new environment
setmetatable(newgt , {__index = _G})
_ENV = newget -- set it
print(a) --> 1

在这个代码中,从老的环境里继承了point 和 a 变量。

任何访问都是去访问新的table。无论怎么去访问,修改都不会对老的环境造成影响,除非通过_G去修改它的值。

作为一个普通的变量,_ENV遵循一般的域规则。

在一个chunk块中定义的函数,在访问其他外部变量时,实际会访问_ENV。

_ENV = {_G = _G}
local function foo()
_G.print(a) --compiled as '_ENV._G.print(_ENV.a)'
end
a = --_ENV.a
foo() --
_ENV = {_G = _G,a = }
foo() --

如果我们定义一个新的_ENV局部变量,当在涉及到自由名字时就会用这个新定义的变量。

a =
do
local _ENV = { print = print, a=}
print(a) --
end
print(a) --2 (back to the orignal _ENV)

因此,定义一个带有私有环境的函数不是什么难事。

function factory(_ENV)
return function()
return a --"global" a
end
end
f1= factory{a = }
f2 = factory{a = }
print(f1()) --
print(f2()) --

factory函数创建了一个返回全局变量a的闭合函数。

当创建闭合函数的时候,这可见的_ENV变量就是闭合函数factory的_ENV参数。

因此,闭合函数就会用这个外部变量(作为上值)访问自由名字。

使用这个域规则,可以用一些其他方法操作环境。

比如,可以用几个函数共享一个环境,或者用一个函数去修改被其他函数共享的环境。

Chapter 14_4 使用_ENV的更多相关文章

  1. Chapter 14_5 _ENV和load

    load在加载代码块时,通常使用全局环境去初始化代码块的_ENV上值. 然而,load选项的第四个参数给出的值就是供_ENV用的.(loadfile函数参数也是一样) 举一个有关初始化的例子,假如我们 ...

  2. Modern C++ CHAPTER 2(读书笔记)

    CHAPTER 2 Recipe 2-1. Initializing Variables Recipe 2-2. Initializing Objects with Initializer Lists ...

  3. Android Programming: Pushing the Limits -- Chapter 7:Android IPC -- ApiWrapper

    前面两片文章讲解了通过AIDL和Messenger两种方式实现Android IPC.而本文所讲的并不是第三种IPC方式,而是对前面两种方式进行封装,这样我们就不用直接把Aidl文件,java文件拷贝 ...

  4. Android Programming: Pushing the Limits -- Chapter 7:Android IPC -- Messenger

    Messenger类实际是对Aidl方式的一层封装.本文只是对如何在Service中使用Messenger类实现与客户端的通信进行讲解,对Messenger的底层不做说明.阅读Android Prog ...

  5. [转]第四章 使用OpenCV探测来至运动的结构——Chapter 4:Exploring Structure from Motion Using OpenCV

    仅供参考,还未运行程序,理解部分有误,请参考英文原版. 绿色部分非文章内容,是个人理解. 转载请注明:http://blog.csdn.net/raby_gyl/article/details/174 ...

  6. 《深入理解计算机系统》 Chapter 7 读书笔记

    <深入理解计算机系统>Chapter 7 读书笔记 链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(货被拷贝)到存储器并执行. 链接的时机 编译时,也就是 ...

  7. 《Linux内核设计与实现》Chapter 3 读书笔记

    <Linux内核设计与实现>Chapter 3 读书笔记 进程管理是所有操作系统的心脏所在. 一.进程 1.进程就是处于执行期的程序以及它所包含的资源的总称. 2.线程是在进程中活动的对象 ...

  8. PRML Chapter 2. Probability Distributions

    PRML Chapter 2. Probability Distributions P68 conjugate priors In Bayesian probability theory, if th ...

  9. PRML Chapter 1. Introduction

    PRML Chapter 1. Introduction 为了防止忘记,要把每章的重要内容都记下来,从第一章开始 2012@3@28 今天又回去稍微翻了一下第一章内容,发现第一次看的时候没有看透,每次 ...

随机推荐

  1. idea新建项目文件名为红色的解决办法

    Perference->version Control ->Directory添加项目路径,vcs选<none> 即可.

  2. C++ 中的计时器

    在Java中,有时候会要测试程序的性能,所以会采用System.currentTimeMillis()等类库函数去测试时间开销. 在C++中同样可以完成此功能. 头文件: #include<ct ...

  3. CentOS7 下安装telnet服务

    今天搞了下 Centos 7 下面升级 openssl 和 openssh ,顺便装了下 telnet # 安装 telnet 避免 ssh 无法登录 yum -y install xinetd te ...

  4. 【Python】使用super初始化超类

    初始化超类的传统方式,在子类的实例中调用超类的__init__()方法. 但是传统的方法有两个问题,比如: 问题1: class MyBaseClass: def __init__(self, val ...

  5. [Jmeter]jmeter之初体验(windows下的jmeter)

    一.环境准备 1.安装JDK(传送门:http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.ht ...

  6. 最受欢迎的iOS第三方SDK

    http://www.raywenderlich.com/forums/viewtopic.php?t=4496

  7. 阅读国外大神对this的分析,自己的总结

    大神的分析地址:http://javascriptissexy.com/understand-javascripts-this-with-clarity-and-master-it/#comment- ...

  8. HDU 5862 Counting Intersections(离散化+树状数组)

    HDU 5862 Counting Intersections(离散化+树状数组) 题目链接http://acm.split.hdu.edu.cn/showproblem.php?pid=5862 D ...

  9. Java语法基础总结

    这次上课我们讲了Java语言中的枚举类型,并进行了一次课堂测试,测试代码如下: public class EnumTest { public static void main(String[] arg ...

  10. meta小解

    meta是html中的一个辅助标签,位于<head>与<title>之间,它能提供用户不可见的信息,数据结构为键值对 meta标签格式<meta http-equiv/n ...