前言#
前面我们讲了lua_gettable和lua_settable两个api,也了解到这两个api的调用会触发table的元方法,index和newindex可以帮助我们很好地实现table字段的初始化和检测给空字段复制的功能,然而有时候我们希望抛开这些包袱,简简单单的来实现取值和赋值,当然对于没有元表或者没有实现index和newindex的table来说是这样的,我们就可以简简单单的赋值和取值,但是对于已经实现了原表的table我们要怎么做呢?Lua的设计者当然想到了这一点,提供了下面的api,我们可以利用它来实现想要的功能。
内容#
lua_rawget##
- 原型:void lua_rawget (lua_State *L, int index);
- 解释:类似于 lua_gettable,但是作一次直接访问(不触发元方法)
lua_rawset##
- 原型:void lua_rawset (lua_State *L, int index);
- 解释:类似于 lua_settable,但是是作一个直接赋值(不触发元方法)。
Usage##
- 首先我们先新建一个文件,将文件命名为rawgettest.lua编写如下:
-- 定义一个table
information =
{
name = "tom",
age = 18,
sex = "man",
}
-- 定义元表
local mt = {
__index = function(table, key)
print("lua --> get value --> I haven't this field : " .. key);
end
,
__newindex = function(table, key, value)
print("lua --> set value --> I haven't this field : " .. key);
print("lua --> but I do this : " .. key.." = "..value);
rawset(table, key, value);
end
}
-- 设置元表
setmetatable(information, mt);
function func_printaddr()
print("\nlua -- > information.address : ")
print(information.address)
end
- 编写c++调用代码如下:
lua_State *L = lua_open();
luaL_openlibs(L);
luaL_dofile(L,"rawgettest.lua"); // 加载执行lua文件
lua_getglobal(L,"information"); // 将全局表压入栈
lua_pushstring(L, "age"); // 将要取的变量压入栈
lua_rawget(L, -2); // 取information.age的值 -->lua_rawget用法
if(lua_isnil(L, -1))
{
printf("c++ --> information.age = nil\n");
}
else
{
printf("c++ --> information.age = %d\n", lua_tointeger(L, -1));
}
lua_pop(L,1); // 弹出栈顶变量
lua_pushstring(L, "address"); // 将要取的变量压入栈
lua_rawget(L, -2); // 取information.address的值 -->lua_rawget用法
if(lua_isnil(L, -1))
{
printf("\nc++ --> information.address = nil\n");
}
else
{
printf("\nc++ --> information.address = %s\n", lua_tostring(L, -1));
}
lua_pop(L,1); // 弹出栈顶变量
lua_pushstring(L, "address"); // 将要赋值的变量压入栈
lua_pushstring(L, "beijing"); // 将赋值的结果压入栈
lua_rawset(L, -3); // 赋值操作 -->lua_rawset用法
lua_getglobal(L, "func_printaddr"); // 调用打印函数
lua_pcall(L, 0, 0, 0);
lua_close(L); //关闭lua环境
- 结果
结论#
- raw的原意是未经加工,也就是原汁原味的意思喽,放在lua的代码里仿佛就表示纯粹的、不会调用元表的附加操作。
- 可以把这一章的结果和上一章做个对比,然后你会发现,仅仅是没有打印我们在元表中所做的注释,其他完全一样,说明这两个api确实可以“”绕过“”元表。
- 可能有人会对最后的打印有疑惑,不明白为什么information.address是有值的,那是因为我们在c++代码里赋值了,虽然不会调用元表,但是赋值也会成功,就是简简单单的赋值,纯粹的、未经加工的。
- 细心的你也许会发现相对于上一篇文章的代码,我只改了4行,真的不是我偷懒,只有这样做才能达到对比的想效果啊。