lua metatable使用和源码分析(三)
浏览:1394次 出处信息
基本类型如何使用元表
在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 (阅读:4688)
- Lua GC 的源码剖析 (2) (阅读:3905)
- Ameba , 一个简单的 lua 多线程实现 (阅读:3592)
- Lua GC 的源码剖析 (4) (阅读:3438)
- 使用 luajit 的 ffi 绑定 zeromq (阅读:3361)
- Proto Buffers in Lua (阅读:3149)
- Lua GC 的源码剖析 (1) (阅读:3075)
- 一个 Lua 内存泄露检查工具 (阅读:3039)
- Lua GC 的源码剖析 (6) 完结 (阅读:2627)
- Lua GC 的源码剖析 (3) (阅读:2344)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
扫一扫订阅我的微信号:IT技术博客大学习
<< 前一篇:lua metatable使用和源码分析(二)
后一篇:free命令中的buffers和cached >>
文章信息
- 作者:hoterran 来源: 运维和开发
- 标签: lua metatable
- 发布时间:2012-09-02 22:28:54
建议继续学习
近3天十大热文
- [55] IOS安全–浅谈关于IOS加固的几种方法
- [53] android 开发入门
- [53] 如何拿下简短的域名
- [52] 图书馆的世界纪录
- [50] Go Reflect 性能
- [50] Oracle MTS模式下 进程地址与会话信
- [48] 【社会化设计】自我(self)部分――欢迎区
- [47] 读书笔记-壹百度:百度十年千倍的29条法则
- [36] 程序员技术练级攻略
- [29] 视觉调整-设计师 vs. 逻辑