闭包(closure):是由一个函数和该函数会访问到的非局部变量(或者是upvalue)组成的,函数是一个么有upvalue的闭包
非局部变量:不在自己定义的域中的局部变量
函数与所有其他的值是一样都是匿名的,即他们没有名称。当讨论一个函数时(例如print),实质上在讨论一个持有某个函数的变量,一个函数定义实质就是一条赋值语句,这条语句创建了一种类型为“函数”的值,并赋值给一个变量
function foo(x) print(x) end
|
实质是等价于
1
|
foo = function (x) print(x) end
|
执行函数:每当Lua执行一个形如function...end 这样的表达式时,他就会创建一个新的数据对象,其中包含了相应函数原型的引用及一个由所有upvalue引用组成的数组,而这个数据对象就称为闭包。
共享。为了保证这种唯一性,Lua 为整个运行栈保存了一个链接着所有正打开着
的upvalue(那些当前正指向栈内局部变量的upvalue)的链表(图4 中未决状态
的局部变量的链表)。当Lua 创建一个新的闭包时,它开始遍历所有的外层局部
变量,对于其中的每一个,若在上述upvalue 链表中找到它,就重用此upvalue,
否则,Lua 将创建一个新的upvalue 并加入链表中。注意,一般情况下这种遍历
过程在探查了少数几个节点后就结束了,因为对于每个被内层函数用到的外层局
部变量来说,该链表至少包含一个与其对应的入口(upvalue)。一旦某个关闭的
upvalue 不再被任何闭包所引用,那么它的存储空间就立刻被回收。
- typedef union Closure {
- CClosure c;
- LClosure l;
- } Closure;
LClosure表示lua的函数,这些函数是由lua虚拟机进行管理的..
- #define ClosureHeader \
- CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \
- struct Table *env
nupvalues:表示upvalue或者upvals的大小(闭包和函数里面的)。
gclist:链接到全局的gc链表。
env:环境,可以看到它是一个table类型的,他里面保存了一些全局变量等。
- typedef struct CClosure {
- ClosureHeader;
- lua_CFunction f;
- TValue upvalue[1];
- } CClosure;
lua_CFunction f: 这个表示所要执行的c函数的原型.
TValue upvalue[1]:这个表示函数运行所需要的一些参数(比如string 的match函数,它所需要的几个参数都会保存在upvalue里面
- LUA_API void lua_pushcclosure (lua_State *L, lua_CFunction fn, int n) {
- Closure *cl;
- lua_lock(L);
- luaC_checkGC(L);
- api_checknelems(L, n);
- ///new一个cclosure
- cl = luaF_newCclosure(L, n, getcurrenv(L));
- cl->c.f = fn;
- L->top -= n;
- ///开始将参数值放到upvalue中.
- while (n--)
- setobj2n(L, &cl->c.upvalue[n], L->top+n);
- setclvalue(L, L->top, cl);
- lua_assert(iswhite(obj2gco(cl)));
- api_incr_top(L);
- lua_unlock(L);
- }
new 闭包结构 赋值c传递过来的指针 取出压入栈中的参数
- typedef struct LClosure {
- ClosureHeader;
- struct Proto *p;
- UpVal *upvals[1];
- } LClosure;
struct Proto *p:这个指针包含了很多的属性,比如变量,比如嵌套函数等等。
UpVal *upvals[1]:这个数组保存了指针 指针指向UpVal 。
当前的堆栈lua_State中它里面包含有GCObject 类型的域叫openupval这个域也就是当前的栈上的所有open的uvalue lua_State 有global_State域
全局堆栈global_State中的UpVal uvhead则是整个lua虚拟机里面所有栈的upvalue链表的头
- UpVal *luaF_findupval (lua_State *L, StkId level) {
- global_State *g = G(L);
- ///得到openupval链表
- GCObject **pp = &L->openupval;
- UpVal *p;
- UpVal *uv;
- ///开始遍历open upvalue。
- while (*pp != NULL && (p = ngcotouv(*pp))->v >= level) {
- lua_assert(p->v != &p->u.value);
- ///发现已存在。
- if (p->v == level) {
- if (isdead(g, obj2gco(p))) /* is it dead? */
- changewhite(obj2gco(p)); /* ressurect it */
- ///直接返回
- return p;
- }
- pp = &p->next;
- }
- ///否则new一个新的upvalue
- uv = luaM_new(L, UpVal); /* not found: create a new one */
- uv->tt = LUA_TUPVAL;
- uv->marked = luaC_white(g);
- ///设置值
- uv->v = level; /* current value lives in the stack */
- ///首先插入到lua_state的openupval域
- uv->next = *pp; /* chain it in the proper position */
- *pp = obj2gco(uv);
- ///然后插入到global_State的uvhead(这个也就是双向链表的头)
- uv->u.l.prev = &g->uvhead; /* double link it in `uvhead' list */
- uv->u.l.next = g->uvhead.u.l.next;
- uv->u.l.next->u.l.prev = uv;
- g->uvhead.u.l.next = uv;
- lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
- return uv;
- }
查找openvalue 找到则返回 找不到新建一个upvalue 添加到openupval链表中和 global_State的uvhead(这个也就是双向链表的头)
- void luaF_close (lua_State *L, StkId level) {
- UpVal *uv;
- global_State *g = G(L);
- ///开始遍历open upvalue
- while (L->openupval != NULL && (uv = ngcotouv(L->openupval))->v >= level) {
- GCObject *o = obj2gco(uv);
- lua_assert(!isblack(o) && uv->v != &uv->u.value);
- L->openupval = uv->next; /* remove from `open' list */
- if (isdead(g, o))
- luaF_freeupval(L, uv); /* free upvalue */
- else {
- ///unlink掉当前的uv.
- unlinkupval(uv);
- setobj(L, &uv->u.value, uv->v);
- uv->v = &uv->u.value; /* now current value lives here */
- luaC_linkupval(L, uv); /* link upvalue into `gcroot' list */
- }
- }
- }
- static void unlinkupval (UpVal *uv) {
- lua_assert(uv->u.l.next->u.l.prev == uv && uv->u.l.prev->u.l.next == uv);
- uv->u.l.next->u.l.prev = uv->u.l.prev; /* remove from `uvhead' list */
- uv->u.l.prev->u.l.next = uv->u.l.next;
- }
从两个列表中移除upvalue
原文点击打开链接