lua 5.2 的 _ENV
lua 5.2 正式发布了,对于 lua 语言本身的修改,重中之重就是对 environment 这个概念的修改。
可以说, 5.1 以前的 environment 已经没有了。environment 对于制造一个安全的沙盒(或是实现 DSL)是一个很重要的语言特性,我以前很喜欢使用,但也很容易用错。这次的修改我认为是一个谨慎的决定,并使得 lua 语言更为精简和严谨了。
我这样理解 5.2 中的 environment 。本质上,lua 取消了原有意义上的 environment 。所以我们可以看到 C Function 不再有环境了。function 、在 lua 中称为 closure ,仅仅只是函数体和 upvalue 的联合体。这简化了 lua 语言本身。全局变量实际上只是一个语法糖,编译时再前面加上了 _ENV.
的前缀。这样,从 load 开始,第一个 chunk 就被加上了 _ENV
这个 upvalue ,然后依次传递下去。
这个设计基本可以取代以前使用 getfenv/setfenv 改变函数环境的方法。但是又不完全等价。总体来说,增加了一些限制,但不太容易写出 bug 的代码了。
比如说,现在想给返回一个独立环境的函数,可以这样写:
function foobar(env) local _ENV = env return function() ... end end
而以前大约是这样:
function foobar(env) return setfenv(function() ... end, env) end
这不太看得出好坏,但是如果是一组函数,就有区别了。5.2 中是这样:
function foobar(env) local _ENV = env local ret = {} function ret.foo() ... end function ret.bar() ... end return ret end
5.1 的等价代码大约是这样:
function foobar(env) local old = getfenv() setfenv(1,env) local ret = {} function ret.foo() ... end function ret.bar() ... end setfenv(1,old) return ret end
或者这样更函数式一点:
function foobar(env) return setfenv( function() local ret = {} function ret.foo() ... end function ret.bar() ... end return ret end , env) () end
getfenv/setfenv 更灵活,却更容易出错。
对于制作沙盒来说,我感觉 lua 5.2 会更为鼓励使用 load 这种运行时的编译行为。即一定程度上的鼓励元编程。(因为取消了 setfenv ,所以给了 load 显式的参数来制定给 chunk 一个新的环境)
btw, 这个语言设计变更的同时也增强了函数式编程的性能。因为 lua 现在可以更方便的合并那些有相同 upvalue 的 closure 了。(从前除了 upvalue 还有 environment ,合并行为更为复杂)
12 月 30 日补充:
如果非要类似 setfenv 的功能, 修改一组函数的 _ENV
大概需要这样做了:
function getfuncs() local _ENV = _ENV local ret = {} function ret.foo() ... end function ret.setfenv(env) _ENV = env end return ret end
Comments
setfenv 中 while循环中,会产生大量闭包,如何减少这种情况呢?
Posted by: Angie | (16) June 18, 2019 04:50 PM
function setfenv(fn, env)
local i = 1
while true do
local name = debug.getupvalue(fn, i)
if name == "_ENV" then
debug.upvaluejoin(fn, i, (function()
return env
end), 1)
break
elseif not name then
break
end
i = i + 1
end
return fn
end
当频繁调用 debug.upvaluejoin(fn, i, (function()
return env
end), 1)
会产生大量的闭包,如何减少这种情况呢?
Posted by: Angie | (15) June 18, 2019 04:49 PM
给不同func加env不行了,以前可以传入不同函数,用setfenv给他们加上相同env的。
现在貌似不行了,是否有好的解决方法?下面这种 func不能获得upvalue啊。。
function addEnv(func)
local _ENV = {}
return func
end
Posted by: lqk | (14) March 17, 2012 12:05 AM
又研究了下,_G除了在最外层为_ENV时,似乎别无他用,是不是有了_ENV,_G就没有用了
Posted by: wangqs | (13) February 6, 2012 04:46 PM
lua新手弱弱地请教,_G和_ENV有什么区别
Posted by: wangqs | (12) February 6, 2012 01:51 PM
云风大哥,你在csdn上成为2011年国内十大IT人物了
http://subject.csdn.net/pandian2011/people.html
Posted by: 青春华航 | (11) January 2, 2012 11:40 PM
感觉lua 5.2做出的修改还是明确并谨慎的,使lua的语义更加精炼、严谨、优雅了(一直觉得setfenv/getfenv很丑,总觉得它不属于语法层面的东东)。不明白为什么人们期待的类似golang中defer的域退出机制还是没提供。没办法自己用lua closure实现了一个,共用了40几行代码。https://github.com/peterk9999/LuaK
语法类似于golang的defer,不同的是支持任何域的退出,而不仅仅是函数体。
function foo()
local f1 = open();
local f2 = open();
defer
f1:close();
f2:close();
end;
end;
有兴趣的同学可以看看,同时希望风哥能给点意见。
Posted by: peterk | (10) January 1, 2012 01:57 PM
@路人菜鸟,zenk
多谢两位的建议,实在不好意思,把云风这都当成论坛了
我是大三下学期才真正认识到计算机专业是干嘛的,也是那个时候才开始认识到编程语言的重要性,所以起步晚了
我没能有云风大哥这样的机遇,很小就能接触编程,我是进入大学才真正开始操作电脑,进来后又没有老师跟我们说清这个专业的地位和应该加强的方面
所以就一切看机缘了,我们有幸机缘巧合认识到计算机重要性的人就真正学了,那些没认识到的就算是打酱油了吧
或许晚了,不过我不信邪,只管继续往前走
Posted by: Ruchee | (9) December 30, 2011 08:04 PM
lua 5.0到5.1算是小修小补,解决的都是就算没有原生语法自己修修补补也能用的问题。lua 5.2就是大改了,总算解决了好多老大难问题,当然也破坏了向后兼容性。有一个用lua 5.1实现的lua 5.0的backport,但估计很难用5.2实现5.1的backport。
Posted by: Atry | (8) December 30, 2011 07:51 PM
这些代码,看得我好晕啊
Posted by: 泥灸 | (7) December 30, 2011 03:42 PM
这些代码,看的到我头晕脑胀的
Posted by: 泥灸 | (6) December 30, 2011 03:41 PM
大四开始做游戏不晚啊,我毕业5年了才开始做游戏,(毕业2年后才开始真正编程,而且是做了3年的WEB),现在是在写游戏服务端,我感觉你要找准方向,要么偏客户端,要么偏服务端,当然,也不是不可以两边都学,只是精力可能没那么多。
Posted by: zenk | (5) December 30, 2011 03:07 PM
@Ruchee
个人认为“学”不重要。更重要的是不断去“做”。如果想做游戏,就不断实践。过程中就会自然发现需要什么,也就知道该学什么。大四了才开始很晚了,不过也不是没有这样的牛人。加油吧。
Posted by: 路人菜鸟 | (4) December 30, 2011 01:45 PM
env是当前env找不到变量,就往上一级env查找,改成closure是把变量往下传,而不是往上找?
Posted by: sx | (3) December 30, 2011 10:32 AM
我就想Lua新版发布,云风不可能不说几句的,呵呵,还是等到了
我现在大四,准备往游戏编程的方向发展,昨晚搜索了一些这方面的建议贴,发现似乎数学和英语异常重要,而且要求有很高的C++水准
我之前是学纯C的,C++尽管知道个大概,但基本上算是没有入门,我打算重头学一遍C++,然后练习下Win32 API编程和MFC,加强一下数据结构的知识
请问云风,我在学校这自学期间需要重点把握哪些方面呢?有没有必要学点图形学或3D数学?概率论和线性代数是不是需要着重看一下?
期待您的解答,谢谢 ^-^
Posted by: Ruchee | (2) December 30, 2011 09:22 AM
sf?
Posted by: Joyfish | (1) December 30, 2011 08:28 AM