[Lua]在C函数中保存状态--注册表,环境表,upvalue
来源:互联网 发布:身体域纳米网络 编辑:程序博客网 时间:2024/05/16 04:04
什么叫做在C函数中保存状态?比如你现在使用Lua调用了C函数Func1,但是Func1中有一些数据在调用完以后保存下来,供以后使用。而这些数据就是所谓的状态,也就是我们需要保存的东东。有人就会说了,Lua调用C时,把所有的需要保存的状态都返回到Lua中,当调用下一个函数时,将需要的状态当做参数再传进去,不错,是一个办法,但是很麻烦。方法一:注册表;方法二:环境;方法三:upvalue。
注册表是一个全局的table,它只能被C代码访问。通常,可以用它来保存那种需要在几个模块中共享的数据;
但是,如果需要保存一个模块的私有数据,那么应该使用环境,与Lua函数一样,每个C函数都有自己的环境table,通常情况下,一个模块内的所有函数共享同一个环境table,由此它们可以共享数据。
最后,C函数也可以拥有upvalue,upvalue是一种与特定函数相关联的Lua值。
注册表
注册表总是位于一个“伪索引”上,这个索引值由LUA_REGISTRYINDEX定义。伪索引就像是一个栈中的索引,但它所关联的值不在栈中;所完这句话,你想到了什么?C++中,使用new开辟空间,这个空间是在堆上开辟的,而指向这个堆的变量却是存放在栈上的。伪索引和这个意思差不多。Lua API中的大多数函数都能接受伪索引,但像lua_remove和lua_insert这种操作栈本身的函数却只能使用普通索引。
注册表是一个普通的Lua table,可以使用任何Lua值(nil除外)来索引它。
注册表是一个普通的Lua table,可以使用任何Lua值(nil除外)来索引它。
#include<iostream>using namespace std;#include<lua.hpp>void registryTestFunc(lua_State* L){ lua_pushstring(L,"Hello"); lua_setfield(L,LUA_REGISTRYINDEX,"key1"); lua_getfield(L,LUA_REGISTRYINDEX,"key1"); printf("%s\n",lua_tostring(L,-1));//输出为:Hello}int main(){ lua_State* L = luaL_newstate(); registryTestFunc(L); lua_close(L); return 0;}
环境表
从5.1开始,在Lua中注册的所有C函数都有自己的环境table。一个函数可以像访问注册表那样,通过一个伪索引来访问它的环境table。环境table的伪索引是LUA_ENVIRONINDEX。
这种使用环境的方法与在Lua模块中使用环境的方法差不多,都是先为模块创建一个新的table,然后使模块中的所有函数都共享这个table。只不过,在Lua中使用了一个setfenv函数,而在C模块中,只不过是设置table为LUA_ENVIRONINDEX
这种使用环境的方法与在Lua模块中使用环境的方法差不多,都是先为模块创建一个新的table,然后使模块中的所有函数都共享这个table。只不过,在Lua中使用了一个setfenv函数,而在C模块中,只不过是设置table为LUA_ENVIRONINDEX
#include<iostream>using namespace std;#include<lua.hpp>int setValue(lua_State* L){ luaL_checkstring(L,-1); lua_pushvalue(L,-1); lua_setfield(L,LUA_ENVIRONINDEX,"key1"); return 0;} int getValue(lua_State* L){ lua_getfield(L,LUA_ENVIRONINDEX,"key1"); return 1;}static luaL_Reg myfuncs[] = { {"setValue", setValue}, {"getValue", getValue}, {NULL, NULL} }; extern "C" __declspec(dllexport) int luaopen_testenv(lua_State* L){ lua_newtable(L); //创建一个新的表用于环境 lua_replace(L,LUA_ENVIRONINDEX); //将刚刚创建并压入栈的新表替换为当前模块的环境表。 luaL_register(L,"testenv",myfuncs); return 1; //这个注册函数比以前写的注册函数要多两行代码,先要创建一个新的table,然后调用lua_replace将新的table作环境table。然后调用luaL_register时,所有新建的函数都会继承当前环境。}test.lua文件内容
require "testenv"local fun1 = function() local var = "Hello,world!!!" testenv.setValue(var) print(testenv.getValue()) --输出Hello,world!!!endxpcall(fun,print)os.execute("pause")上面先将值设置到模块环境table中。然后再从中取出来。这个和上面说的注册表有很多的相似之处。尽管可能使用环境来代替注册表,但是如果没有在不同模块之间共享数据的需要,就尽可能的不要使用注册表;使用环境创建的引用,只是在本模块中可见,这样缩小了数据的使用范围了,减小了数据被错改的可能,增加了数据的安全性。
upvalue
upvalue是和特定函数关联的,我们可以将其简单的理解为函数内的静态变量。
注册表提供了全局变量的存储,环境提供了模块变量的存储,而upvalue机制则实现了一种类似于C语言中静态变量的机制。而这种upvalue机制,可以让我们定义一个只在特定的函数中可见的变量。每当在Lua中创建一个函数时,都可以将任意数量的upvalue与这个函数相关联。每个upvalue都可以保存一个Lua值。以后,在调用这个函数时,就可以通过伪索引来访问这些upvalue了。将这种C函数与upvalue的关联称为closure(也叫闭包,多么熟悉的名字)。一个C closure类似于Lua closure。closure可以用同一个函数代码来创建多个closure,每个closure可以拥有不同的upvalue。
注册表提供了全局变量的存储,环境提供了模块变量的存储,而upvalue机制则实现了一种类似于C语言中静态变量的机制。而这种upvalue机制,可以让我们定义一个只在特定的函数中可见的变量。每当在Lua中创建一个函数时,都可以将任意数量的upvalue与这个函数相关联。每个upvalue都可以保存一个Lua值。以后,在调用这个函数时,就可以通过伪索引来访问这些upvalue了。将这种C函数与upvalue的关联称为closure(也叫闭包,多么熟悉的名字)。一个C closure类似于Lua closure。closure可以用同一个函数代码来创建多个closure,每个closure可以拥有不同的upvalue。
#include<iostream>using namespace std;#include<lua.hpp>int counter(lua_State* L){ //获取第一个upvalue的值。 int val = lua_tointeger(L,lua_upvalueindex(1)); //将得到的结果压入栈中。 lua_pushinteger(L,++val); //赋值一份栈顶的数据,以便于后面的替换操作。 lua_pushvalue(L,-1); //该函数将栈顶的数据替换到upvalue(1)中的值。同时将栈顶数据弹出。 lua_replace(L,lua_upvalueindex(1)); //lua_pushinteger(L,++value)中压入的数据仍然保留在栈中并返回给Lua。 return 1;}int newCounter(lua_State* L){ //压入一个upvalue的初始值0,该函数必须先于lua_pushcclosure之前调用。 lua_pushinteger(L,0); //压入闭包函数,参数1表示该闭包函数的upvalue数量。该函数返回值,闭包函数始终位于栈顶。 lua_pushcclosure(L,counter,1); return 1;}static luaL_Reg myfuncs[] = { {"counter", counter}, {"newCounter", newCounter}, {NULL, NULL} }; extern "C" __declspec(dllexport) int luaopen_testupvalue(lua_State* L){ luaL_register(L,"testupvalue",myfuncs); return 1;}test.lua文件内容
require "testupvalue"local fun = function() func = testupvalue.newCounter(); print(func()); print(func()); print(func()); func = testupvalue.newCounter(); print(func()); print(func()); print(func()); --[[ 输出结果为: 1 2 3 1 2 3 --]]endxpcall(fun,print)os.execute("pause")
0 0
- [Lua]在C函数中保存状态--注册表,环境表,upvalue
- [Lua]在C函数中保存状态--注册表,环境表,upvalue
- lua 在C函数中保存状态:registry、reference和upvalues
- 在C 函数中保存状态:registry、reference和upvalues
- 在C函数中保存状态:registry、reference和upvalues
- lua如何在游戏中保存上一次游戏状态
- lua如何在游戏中保存上一次游戏状态
- Lua upvalue 函数 闭包
- CImage在OnPaint()函数中保存图片
- [lua] lua 函数 upvalue 数量限制
- 如何在视图状态中保存自定义的对象
- 16.4 在有响应的应用程序中保存状态
- Spring MVC不要在@Service bean中保存状态
- Android中保存界面状态
- lua upvalue
- Lua upvalue
- 注册表中保存的VC安装路径
- C语言中保存数据的万能函数
- RDLC后台自定义报表模板
- 监控 SQL Server 的运行状况
- 优先队列 算法导论 java语言
- VIM技巧之分隔窗口
- 抽象类和接口
- [Lua]在C函数中保存状态--注册表,环境表,upvalue
- SVN 树冲突和目录丢失问题
- 需求采集人人有责
- JAVA+ffmpeg+mencoder转换视频
- HTTP协议请求与响应格式内容详解
- Spring之思
- Android Studio安装以及Fetching android sdk component information超时的解决方案
- 美国麻省理工教授亲授科研学习方法(下)
- IOS UIButton使用详解