云风的lua源码赏析对元表部分一带而过,估计是觉得太low。幸好还有 hoterran网友在做分析,以下很多文字参考他的。
先看一个例子:
person = {} person.mp = 1 print(person.hp)
但是如果添加元表就不一样了:
person = {} person.mp = 1 base = {} base.hp = 10 setmetatable(base, {__index = function() return ("hey guy u call a unexisted table member!!") end}) setmetatable(person, {__index = base}) print(person.hp) print(person.wp)
>lua -e "io.stdout:setvbuf ‘no‘" "tt.lua"
10
hey guy u call a unexisted table member!!
>Exit code: 0
这里将base表作为person的元表,如果在person里找不到的key就会向元表里找,hp就找到了,wp找不到就打印那段提示啦,哈哈。
那lua内部是如何实现设置元表并如何在table.key/fun时查询相关元表呢?
1、设置元表
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")) return luaL_error(L, "cannot change a protected metatable"); lua_settop(L, 2); lua_setmetatable(L, 1); return 1; }
就table来说,它有metatable字段,调用此函数
2、如何如果设置了__index,那是调用元表?
在
void luaV_execute (lua_State *L) 里会解析到opcode进行事件分发:
for (;;) { Instruction i = *(ci->u.l.savedpc++); StkId ra; if ((L->hookmask & (LUA_MASKLINE | LUA_MASKCOUNT)) && (--L->hookcount == 0 || L->hookmask & LUA_MASKLINE)) { Protect(traceexec(L)); } /* WARNING: several calls may realloc the stack and invalidate `ra‘ */ ra = RA(i); lua_assert(base == ci->u.l.base); lua_assert(base <= L->top && L->top < L->stack + L->stacksize); vmdispatch (GET_OPCODE(i)) { vmcase(OP_GETTABLE, Protect(luaV_gettable(L, RB(i), RKC(i), ra)); )
void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) { int loop; for (loop = 0; loop < MAXTAGLOOP; loop++) { const TValue *tm; if (ttistable(t)) { /* `t‘ is a table? */ Table *h = hvalue(t); const TValue *res = luaH_get(h, key); /* do a primitive get */ if (!ttisnil(res) || /* result is not nil? */ (tm = fasttm(L, h->metatable, TM_INDEX)) == NULL) { /* or no TM? */ setobj2s(L, val, res); return; } /* else will try the tag method */ } else if (ttisnil(tm = luaT_gettmbyobj(L, t, TM_INDEX))) luaG_typeerror(L, t, "index"); if (ttisfunction(tm)) { callTM(L, tm, t, key, val, 1); return; } t = tm; /* else repeat with ‘tm‘ */ } luaG_runerror(L, "loop in gettable"); }
/* ** function to be used with macro "fasttm": optimized for absence of ** tag methods */ const TValue *luaT_gettm (Table *events, TMS event, TString *ename) { const TValue *tm = luaH_getstr(events, ename); lua_assert(event <= TM_EQ); if (ttisnil(tm)) { /* no tag method? */ events->flags |= cast_byte(1u<<event); /* cache this fact */ return NULL; } else return tm; }
这样看下来,文章最前面写的lua例子就容易理解了。
lua中metatable源码分析总结,布布扣,bubuko.com
原文:http://blog.csdn.net/boyxiaolong/article/details/24144407