您的位置:首页 > 娱乐 > 八卦 > 百度网站改版_网络营销课程性质_长春网站建设技术支持_上海网络推广

百度网站改版_网络营销课程性质_长春网站建设技术支持_上海网络推广

2025/1/13 6:03:25 来源:https://blog.csdn.net/weixin_42341040/article/details/144189575  浏览:    关键词:百度网站改版_网络营销课程性质_长春网站建设技术支持_上海网络推广
百度网站改版_网络营销课程性质_长春网站建设技术支持_上海网络推广

闭包

lua任何函数都是闭包,闭包至少带1个upValue;

CClosure是使用Lua提供的lua_pushcclosure这个C-Api加入到虚拟栈中的C函数,它是对LClosure的一种C模拟

如string.gmatch就是cclosure

定义:

#define ClosureHeader \CommonHeader; lu_byte isC; lu_byte nupvalues; GCObject *gclist; \struct Table *envtypedef struct CClosure {ClosureHeader;lua_CFunction f;TValue upvalue[1];
} CClosure;typedef struct LClosure {ClosureHeader;struct Proto *p;UpVal *upvals[1];
} LClosure;typedef union Closure {CClosure c;LClosure l;
} Closure;

上值

local a = 1
local b = 2
function xxx()local c = 3local d = 4print(a + b)function yyy()print(c + d)end
end

在这里插入图片描述

我们可以看到,每个lua函数,都有一个upvalue列表,并且他们首个upvalue,都是一个名为_ENV的upvalue,内层lua函数的_ENV指向外层lua函数的_ENV,而最外层的top-level函数,则将值指向了全局表_G。为什么lua要用这种组织方式?将_ENV作为每个lua函数的第0个upvalue呢?我认为,这是为了效率,同时也能是的逻辑更为清晰,lua函数去查找一个变量的方式,如下所示:

lua函数查找一个变量v,首先会在自己的local变量中查找,如果找到就直接获取它的值,找不到则进入下一步
查找upvalue列表,有没有一个名为v的upvalue,有则获取它的值,没有则进入下一步
到_ENV里去查找一个名为v的值

上值的确定(编译期)

用来表示upvalue的有两个数据结构,一个是编译时期,存储upvalue信息的Upvaldesc(这个结构并不存储upvalue的实际值,只是用来标记upvalue的位置信息),还有一个是在运行期,实际存储upvalue值的UpVal结构。它们的结构定义如下所示:

typedef struct upvaldesc {lu_byte in_stack;lu_byte idx;TString* name;
} upvaldesc;typedef struct  UpVal {CommonHeader;TValue *v;  /* points to stack or to its own value */union {// 当这个upval被close时,保存upval的值,后面可能还会被引用到TValue value;  /* the value (when closed) */// 当这个upval还在open状态时,以下链表串连在openupval链表中struct {  /* double linked list (when open) */struct UpVal *prev;struct UpVal *next;} l;} u;
} UpVal;

举例:

local a = 1
local b = 2
function xxx()local c = 3print(a)function yyy()print(a+b+c)end
end

编译期确定upvalue,最终的结构如下:
在这里插入图片描述
LClosure实际是运行时才会实例化的,这里为了展示方便;
分成3个level, top level, level2, level3;
top level: Upvaldesc列表只有1个,指代_ENV
level2: Upvaldesc列表有3个,第一个是_ENV, 是上一级的上值列表的第一个(所以in_stack=0,idx=0); 第二个是变量a, 是上一级的局部变量在栈上第一个(所以in_stack=1,idx=0);第三个是变量b, 是上一级的局部变量在栈上第二个(所以in_stack=1,idx=1)
level3: Upvaldesc列表有4个,第一个是_ENV, 是上一级的上值列表的第一个(所以in_stack=0,idx=0); 第二个是变量a, 是上一级的上值列表的第二个(所以in_stack=0,idx=1);第三个是变量b, 是上一级的上值列表的第三个(所以in_stack=0,idx=2);第四个是变量c,是上一级局部变量在栈上第一个(所以in_stack=1,idx=0)

上值生成(运行时)

当加载这段代码块时,level2的upval列表会加入2个UpVal,指向栈(变量a和b);level3的UpVal不会生成因为没有调用xxx
在这里插入图片描述
当调用xxx时,最终生成的upval列表如下
在这里插入图片描述

上值的open和close

如下图的代码段,当调用aaa()时,var1和var2都在栈上,处于open状态,UpVal结构的v指针指向栈上数据
在这里插入图片描述
但是aaa调用完毕,var2会被回收,弹出栈,如下:
在aaa函数执行完毕时,他们的UpVal实例,会进行close操作,什么意思呢,就是原来的upval->v指向栈的某个位置,现在这个关联将被破除,并且upval->v的值,赋值为upval->u.value的地址,同时,upval->v原来指向的值,会被赋值到upval->u.value上(绿色框2个UpVal指向了新的空间)
在这里插入图片描述

闭包共享/不共享上值

f1和f2分别创建了一个闭包实例,var1是top level的局部变量,能共享;var2则是独立上值,且在aaa()调用完毕后会从栈上移除,转为close状态(可以看到var2的UpVal结构,v指针不是指向栈,而是union中的TValue结构)
在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com