|
于 2011-8-27 22:46, Jeff Smith 写道:
a light userdata is just a "pointer". lua code can only do assignment and test the equality of userdata, all other operations (e.g. index) must be defined in C code. simply saying, you store a C pointer into lua using light userdata, and define various operations that can be access from lua as metamethods. for instance, you know, the lua code `myFoo.x' is actually syntax suggar for 'myFoo["x"]', which is a *index* operation with a key of the "string" type. so if you want to access myFoo.x and myFoo.y from lua like this ------------------ local x = myFoo.x local y = myFoo.y ------------------ you should : 1. put a light userdata, or pointer (which points to the C struct `myFoo'), into lua, with the (global) name `myFoo' ---------------------------------- lua_pushlightuserdata(L, (void*)&myFoo); lua_setglobal(L, "myFoo"); ---------------------------------- 2. define the *index* operation (e.g. as a lua_CFunction) that accept the string "x" and "y" as key and return the x and y member of the C struct respectively. ----------------------------------- int foo_indexer (lua_State *L) { struct foo * p = lua_touserdata(L, 1); const char *key = lua_tostring(L, 2); if (p != NULL & key != NULL) { if ( key[0] == 'x' && key[1] == '\0') { // key is "x" lua_pushinteger(L, p->x); return 1; } else if ( key[0] == 'y' && key[1] == '\0') { // key is "y" lua_pushinteger(L, p->y); return 1; } } return 0; } ------------------------------------ 3. assiociate the index operation with the userdata. through metamethod __index ------------------------------------ lua_getglobal(L, "myFoo"); lua_newtable(L); lua_pushcfunction(L, &foo_indexer); lua_setfield(L, -2, "__index"); lua_setmetatable(L, -2); lua_pop(L, -1); ------------------------------------- then, in lua, the global myFoo is now a lightuser data. but lua code can only assign it to other variable, or compare it with other value for equality, or index it, all other operations would give a error, since we have only defined the `__index' metamethod. ------------------------------------- local x = myFoo.x -- metacall foo_indexer(myFoo, "x") mt = getmetatable(myFoo) -- mt.__index == foo_indexer print(type(x), type(myFoo["y"]), type(myFoo.bar), type(myFoo[1])) -- would print : Number Number Nil Nil myBar = myFoo -- assignment assert( myBar == myFoo) -- equality test myFoo.x = 100 -- issue a error message something like "newindex operation is not defined" -------------------------------------- one thing to note: all light userdata values in a same lua (global) State share a same metatable. in other words, metatable for light userdata is not "per object". the code I show is demostrating and not tested. the important thing is to understand the concepts. Hopefully may help. |