lua metatable使用和源码分析(三)
浏览:1732次 出处信息
基本类型如何使用元表
在lua里只能为表设置元表,而在c程序里面可以为基本类型进行元表操作,但上篇博文提到了普通类型的很多操作是不会走到元表,下面的例子针对数字类型,添加多种事件,只有部分事件会生效.下面的例子在c代码里对数字类型添加元表对__add,__len都设置事件.
mct.c
======================
#include
#include
#include
//__add event function
static int add(lua_State *L) {
lua_pushinteger(L, 200);
return 1;
}
//__len event function
static int len(lua_State *L) {
lua_pushinteger(L, 111);
return 1;
}
int main(int argc, char* argv[]) {
lua_State *L = lua_open();
luaopen_base(L);
//integer type metatable
lua_pushnumber(L, 1);
lua_newtable(L);
lua_pushcfunction(L, add);
lua_setfield(L, -2, "__add");
lua_pushcfunction(L, len);
lua_setfield(L, -2, "__len");
lua_setmetatable(L, -2);
if(luaL_loadfile(L, "meta_c_test.lua") || lua_pcall(L, 0, 0, 0)) {
printf("error %s\\n", lua_tostring(L, -1));
return;
}
lua_close(L);
return 0;
}
再来看meta_c_test.lua脚本
hoterran@~/Projects/lua$ cat meta_c_test.lua
print(#1)
print(1 + 2)
print(getmetatable(1))
print(getmetatable(""))
hoterran@~/Projects/lua$ ./mct
100
3
table: 0x87e7950
nil
这个lua程序在普通的lua解释器下是回报错的,因为数字类型并未有计算长度的函数.当给数字类型设置元表后,__len成功的执行了,而__add并未调用元表事件函数,这符合我们在上一篇博文里的分析.同时可以发现数字类型已经设置了一个元表,而其它基本类型的元表都是为nil的.
利用 _metatable事件来保护元表不会被修改
_metatable可以隐藏元表信息,一旦设置后元表就不能再被修改了.
hoterran@~/Projects/lua$ cat meta_metatable.lua
d = {}
setmetatable(d, {__index = function(x) return 111 end})
print(d.aa) ---- 111
print(getmetatable(d))
setmetatable(d, {__metatable = "aaaa"})
print(getmetatable(d)) ---- metable信息被隐藏,打印出__metatable里信息aaaa--cant call
--setmetatable(d, {__index = function(x) return 222 end}) ---这句会报错,元表不再能被修改.
设置元表的时候如果发现有__metatable的事件信息则报错退出,停止设置元表
static int luaB_setmetatable (lua_State *L) {
int t = lua_type(L, 2);
luaL_checktype(L, 1, LUA_TTABLE);
luaL_argcheck(L, t == LUA_TNIL || t == LUA_TTABLE, 2, "nil or table expected");
if (luaL_getmetafield(L, 1, "__metatable"))
luaL_error(L, "cannot change a protected metatable");
lua_settop(L, 2);
lua_setmetatable(L, 1);
return 1;
}
查找元表之后,如果还存在__metatable事件,返回该事件对应的信息并把已经获取到的元表弹出栈.
static int luaB_getmetatable (lua_State *L) {
luaL_checkany(L, 1);
if (!lua_getmetatable(L, 1)) {
lua_pushnil(L);
return 1; /* no metatable */
}
luaL_getmetafield(L, 1, "__metatable");
return 1; /* returns either __metatable field (if present) or metatable */
}
利用元表来保护userdata不被误用
因为userdata是个指针容易被误用,所以元表的作用就是给它取个名字,使得在操作userdata的时候比较名字是否一致.这里代码不展示了,介绍一些原理.
luaL_newmetatable会创建一个键值名和空元表挂到LUA_REGISTRYINDEX,
lua_setmetatable为userdata设置元表之后,操作userdata的时候会调用lua_checkudata根据键值从REGISTRYINDEX获得这个元表并与userdata内的元表进行比较看是否相同,否则不能操作这个userdata.
好了基本上metatable的用法就是这些,有不对的地方还请帮忙指出,谢.
建议继续学习:
- Nginx与Lua (阅读:5293)
- Lua GC 的源码剖析 (2) (阅读:4603)
- Ameba , 一个简单的 lua 多线程实现 (阅读:4403)
- Lua GC 的源码剖析 (4) (阅读:4207)
- 使用 luajit 的 ffi 绑定 zeromq (阅读:3908)
- Proto Buffers in Lua (阅读:3883)
- Lua GC 的源码剖析 (1) (阅读:3824)
- 一个 Lua 内存泄露检查工具 (阅读:3617)
- Lua GC 的源码剖析 (6) 完结 (阅读:3410)
- Lua GC 的源码剖析 (3) (阅读:3050)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
扫一扫订阅我的微信号:IT技术博客大学习
<< 前一篇:lua metatable使用和源码分析(二)
后一篇:free命令中的buffers和cached >>
文章信息
- 作者:hoterran 来源: 运维和开发
- 标签: lua metatable
- 发布时间:2012-09-02 22:28:54
建议继续学习
近3天十大热文
-
[930] WordPress插件开发 -- 在插件使用 -
[130] 解决 nginx 反向代理网页首尾出现神秘字 -
[51] 如何保证一个程序在单台服务器上只有唯一实例( -
[51] 海量小文件存储 -
[50] 整理了一份招PHP高级工程师的面试题 -
[49] CloudSMS:免费匿名的云短信 -
[48] 全站换域名时利用nginx和javascri -
[48] 用 Jquery 模拟 select -
[47] Innodb分表太多或者表分区太多,会导致内 -
[46] ps 命令常见用法
