用户数据示例 |
|
此 Lua 5.0 示例展示了如何在用户数据中存储结构。
另一种方法是仅在用户数据中存储单个指针。请参阅 UserDataWithPointerExample。
用户数据的元表被放入注册表中,__index 字段指向方法表,以便 object:method() 语法可以正常工作。方法表存储在全局表中,以便脚本可以添加用 Lua 编写的其他方法。
使用该结构的 Lua 函数需要访问堆栈上的用户数据,或者将新的用户数据推送到堆栈上。
checkFoo 确保堆栈上的用户数据类型正确,并返回指向用户数据内部结构的指针。
pushFoo 将新的用户数据留在堆栈顶部,设置其元表,并返回指向结构的指针,以便您可以填写字段。
#include "lua.h"
#include "lauxlib.h"
#define FOO "Foo"
typedef struct Foo {
int x;
int y;
} Foo;
static Foo *toFoo (lua_State *L, int index)
{
Foo *bar = (Foo *)lua_touserdata(L, index);
if (bar == NULL) luaL_typerror(L, index, FOO);
return bar;
}
static Foo *checkFoo (lua_State *L, int index)
{
Foo *bar;
luaL_checktype(L, index, LUA_TUSERDATA);
bar = (Foo *)luaL_checkudata(L, index, FOO);
if (bar == NULL) luaL_typerror(L, index, FOO);
return bar;
}
static Foo *pushFoo (lua_State *L)
{
Foo *bar = (Foo *)lua_newuserdata(L, sizeof(Foo));
luaL_getmetatable(L, FOO);
lua_setmetatable(L, -2);
return bar;
}
static int Foo_new (lua_State *L)
{
int x = luaL_optint(L, 1, 0);
int y = luaL_optint(L, 2, 0);
Foo *bar = pushFoo(L);
bar->x = x;
bar->y = y;
return 1;
}
static int Foo_yourCfunction (lua_State *L)
{
Foo *bar = checkFoo(L, 1);
printf("this is yourCfunction\t");
lua_pushnumber(L, bar->x);
lua_pushnumber(L, bar->y);
return 2;
}
static int Foo_setx (lua_State *L)
{
Foo *bar = checkFoo(L, 1);
bar->x = luaL_checkint(L, 2);
lua_settop(L, 1);
return 1;
}
static int Foo_sety (lua_State *L)
{
Foo *bar = checkFoo(L, 1);
bar->y = luaL_checkint(L, 2);
lua_settop(L, 1);
return 1;
}
static int Foo_add (lua_State *L)
{
Foo *bar1 = checkFoo(L, 1);
Foo *bar2 = checkFoo(L, 2);
Foo *sum = pushFoo(L);
sum->x = bar1->x + bar2->x;
sum->y = bar1->y + bar2->y;
return 1;
}
static int Foo_dot (lua_State *L)
{
Foo *bar1 = checkFoo(L, 1);
Foo *bar2 = checkFoo(L, 2);
lua_pushnumber(L, bar1->x * bar2->x + bar1->y * bar2->y);
return 1;
}
static const luaL_reg Foo_methods[] = {
{"new", Foo_new},
{"yourCfunction", Foo_yourCfunction},
{"setx", Foo_setx},
{"sety", Foo_sety},
{"add", Foo_add},
{"dot", Foo_dot},
{0, 0}
};
static int Foo_gc (lua_State *L)
{
printf("bye, bye, bar = %p\n", toFoo(L, 1));
return 0;
}
static int Foo_tostring (lua_State *L)
{
char buff[32];
sprintf(buff, "%p", toFoo(L, 1));
lua_pushfstring(L, "Foo (%s)", buff);
return 1;
}
static const luaL_reg Foo_meta[] = {
{"__gc", Foo_gc},
{"__tostring", Foo_tostring},
{"__add", Foo_add},
{0, 0}
};
int Foo_register (lua_State *L)
{
luaL_openlib(L, FOO, Foo_methods, 0); /* create methods table,
add it to the globals */
luaL_newmetatable(L, FOO); /* create metatable for Foo,
and add it to the Lua registry */
luaL_openlib(L, 0, Foo_meta, 0); /* fill metatable */
lua_pushliteral(L, "__index");
lua_pushvalue(L, -3); /* dup methods table*/
lua_rawset(L, -3); /* metatable.__index = methods */
lua_pushliteral(L, "__metatable");
lua_pushvalue(L, -3); /* dup methods table*/
lua_rawset(L, -3); /* hide metatable:
metatable.__metatable = methods */
lua_pop(L, 1); /* drop metatable */
return 1; /* return methods on the stack */
}
int main(int argc, char *argv[])
{
lua_State *L = lua_open();
luaopen_base(L);
luaopen_table(L);
luaopen_io(L);
luaopen_string(L);
luaopen_math(L);
luaopen_debug(L);
Foo_register(L);
lua_pop(L, 1); //After foo register the methods are still on the stack, remove them.
if(argc>1) lua_dofile(L, argv[1]);
lua_close(L);
return 0;
}
此代码可以按如下方式为 Lua 5.0 编译
gcc foo.c -L/usr/local/lib -llua -llualib
for n,v in Foo do print(n,v) end local a = Foo.new() local b = Foo.new(99,100) MyFunction = Foo.yourCfunction print(a, MyFunction(a)) print(b, MyFunction(b)) function Foo:show(msg) print(msg, self, self:yourCfunction()) return self end function Foo:point(t) assert(type(t) == 'table') self:setx(t.x or t[1]):sety(t.y or t[2]) return self end setmetatable(Foo, { __call = function(self, x, y) local bar = self.new(x,y) print('created', bar) return bar end } ) local p = Foo(1,2) p:show('p is') p:setx(3):show'p is':sety(4):show'p is' p:point{33,44}:show'p is' p = nil collectgarbage() a:point{x=500, y=1000} a:show'a is' r = Foo.add(a,b) r:show'r is' a:show'a is' b:show'b is' s = a + b s:show's is' --debug.debug()
$ ./a test.lua sety function: 0xa045388 dot function: 0xa045328 setx function: 0xa044fb8 yourCfunction function: 0xa0452c8 add function: 0xa0452f8 new function: 0xa044f80 this is yourCfunction Foo (0xa046938) 0 0 this is yourCfunction Foo (0xa046760) 99 100 created Foo (0xa045458) this is yourCfunction p is Foo (0xa045458) 1 2 this is yourCfunction p is Foo (0xa045458) 3 2 this is yourCfunction p is Foo (0xa045458) 3 4 this is yourCfunction p is Foo (0xa045458) 33 44 bye, bye, bar = 0xa045458 this is yourCfunction a is Foo (0xa046938) 500 1000 this is yourCfunction r is Foo (0xa045478) 599 1100 this is yourCfunction a is Foo (0xa046938) 500 1000 this is yourCfunction b is Foo (0xa046760) 99 100 this is yourCfunction s is Foo (0xa046470) 599 1100 bye, bye, bar = 0xa046470 bye, bye, bar = 0xa045478 bye, bye, bar = 0xa046760 bye, bye, bar = 0xa046938
luaopen_base(L); luaopen_table(L); luaopen_io(L); luaopen_string(L); luaopen_math(L); luaopen_debug(L);
用
luaL_openlibs(L);
以避免 luaopen_io(L) 出现问题。有关详细信息,请参阅 [此列表消息]。
替换(在 main() 中)
if(argc>1) lua_dofile(L, argv[1]);
用
if (argc > 1) {
int s = luaL_loadfile(L, argv[1]);
if (s == 0) {
s = lua_pcall(L, 0, LUA_MULTRET, 0);
}
}
编译(5.1.4)
gcc foo.c -L/usr/local/lib -llua -ldl -lm
test.lua 的第一行需要修改为使用 pairs() 函数
for n,v in pairs(Foo) do print(n,v) end