Lu userdata

Lua userdata教程

Lua 作为一门嵌入式的可扩展语言,其本身的功能很精简,很多扩展功能需要由 C 语言C++ 提供。而作为扩展功能的一个重要支持就是 userdata,有了 userdata 之后,宿主程序可以把自己的对象模型封装给 Lua 调用。

userdata 本身只是一个指针(light userdata),或一块受 Lua 管理的内存块(full userdata),它没有任何预定义行为,在 Lua 看来它就是一个值,你需要提供配套的 C 函数去操作它。或者给 userdata 加上元表(只有 full userdata 才可以),使得它可以像这样调用 udata:dosomething(),Lua 的 io 库即利用了 userdata 和元表来封装文件操作。

Lua userdata使用

  1. Lua 中使用 userdata 类型来表示在 C 中定义的类型。userdata 只是提供了一块原始的内存区域,可以用来存储任何东西,并且,在 lua 中 userdata 没有任何预定义的操作。在 C 中调用函数 lua_newuserdata 会根据指定的大小分配一块内存,并将相应的 userdata 压入栈中,最后返回这个内存块的地址:void *lua_newuserdata(lua_State*L,size_t size)

  2. 实质在 C 中定义 lua 的 userdata,与定义 C 模块完全类似,只不过通常这时需要通过调用 lua_newuserdata 来告诉 lua 分配一块额外的内存,而在内存所有相关的操作都是在 C 中的定义的,实质就是 C 模块中的接口。注意这块分配的额外内存是由 Lua 垃圾收集器来管理的,无须关心起释放等情况。

  3. 在实现一个 Lua 的程序库或 userdate,必须保证该库或 userdata 的接口不应破坏 C 数据或在 Lua 中导致 core dump。

  4. 可以为每种 userdata 创建一个唯一的元表,来辨别不同类型的 userdata,每当创建了一个 userdata 后,就用相应的元表来标记它,而每得到一个 userdata 后,就检查它是否拥有正确的元表,注意 Lua 代码中不能改变 userdata 的元表(当能增加已有元表的属性,比如对元表 key 为 __index 赋值)。通常是将这个元表存储在注册表中,也类型名作为 key,元表为 value。辅助库提供了一些函数来实现这些:

    int luaL_newmetatable(lua_State*L, const char *tname); void luaL_getmetatable(lua_State *L,const char *tnaem); void *luaL_checkudata(lua_State*L,int index,const char *tname);
  5. 轻量级 userdata 是一种表示 C 指针的值(即 void*),要将一个轻量级 userdata 放入栈中,只需要调用 lua_pushlightuserdata 即可。轻量级 userdata 只是一个指针而已。它没有元表,就像数字一样,轻量级 userdata 无须受垃圾收集器的管理。

  6. Lua 在释放完全 userdata 所关联的内存时,若发现 userdata 对应的元表还有 __gc 元方法,则会调用这个方法,并以 userdata 自身作为参数传入。利用该特性,可以再回收 userdata 的同时,释放与此 userdata 相关联的资源。