用户数据示例

lua-users home
wiki

描述

此 Lua 5.0 示例展示了如何在用户数据中存储结构。

另一种方法是仅在用户数据中存储单个指针。请参阅 UserDataWithPointerExample

用户数据的元表被放入注册表中,__index 字段指向方法表,以便 object:method() 语法可以正常工作。方法表存储在全局表中,以便脚本可以添加用 Lua 编写的其他方法。

使用该结构的 Lua 函数需要访问堆栈上的用户数据,或者将新的用户数据推送到堆栈上。

checkFoo 确保堆栈上的用户数据类型正确,并返回指向用户数据内部结构的指针。

pushFoo 将新的用户数据留在堆栈顶部,设置其元表,并返回指向结构的指针,以便您可以填写字段。

foo.c C 代码

#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

Lua 测试代码

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

用于 Lua 5.1.1 的修改

替换 main() 中的 luaopen 函数
  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

我认为最好是为 5.1 重写页面。--JohnBelmonte

最近更改 · 偏好设置
编辑 · 历史记录
最后编辑于 2015 年 1 月 27 日下午 8:52 GMT (差异)