Lua中的userdata和lightuserdata是什么?

30
  • 什么是Lua中的userdata和lightuserdata?
  • 我在哪里需要使用它们?

我一直在尝试理解这个问题,但似乎找不到任何我真正理解的教程/解释。

为什么需要它们,为什么不能直接将C函数绑定到Lua元表中?


1
元表必须附加到某个东西上,用户数据是一个合理的选择。 - Textmode
4个回答

59

userdata是一个大小和内容任意的垃圾回收值。您可以使用C API创建一个userdata,用lua_newuserdata()函数创建并将其推送到堆栈上,并提供一个指针以便您从C中初始化它。

它非常类似于调用malloc()。与malloc()的一个关键区别是,您永远不需要调用free(),而是只需允许最后一个引用消失,垃圾回收器将最终回收其存储空间。

它们最有用的是用于保存从C有用但必须从Lua管理的数据。它们支持单独的元表,这是绑定C或C++对象到Lua的关键特性。您只需填充其元表,使用在C中编写的方法来访问、修改和/或使用userdata的内容,结果就是一个可以从Lua访问的对象。一个很好的例子是io,它在userdata中存储C的FILE *指针,并提供实现熟悉的readwrite等方法的绑定。通过实现__gc元方法,io库确保其中一个file对象在收集时关闭关联的FILE *

轻量用户数据是在Lua中将指针表示为值的方式。您可以通过使用其值的指针调用lua_pushlightuserdata()来创建一个轻量用户数据。它们由Lua来管理,就像数字一样。当您需要以某种方式命名C对象以便在Lua内部传递名称,但该对象的生命周期未由Lua管理时,它们非常有用。与数字相等当它们具有相同的值时,轻量用户数据在持有相同指针时相等。与数字类似,只要它们位于堆栈上或存储在变量中,它们就存在,并且它们没有单独的元表,也不会被垃圾收集。


7
用户数据是来自C端的数据,可以在Lua中使用。例如,像io.input这样的文件句柄就是用户数据(尝试打印print(type(io.input)))。如果您开始使用Lua C-API(或使用newproxy函数),则需要它自己,该函数会给您一个空的用户数据,您可以在其上设置元表(请参见Lua-users wiki上的Hidden Features:http://lua-users.org/wiki/HiddenFeatures)。
一个很好的介绍链接是:http://www.lua.org/pil/28.html 至于C函数方面:是的,您可以将C函数注册为从Lua内部调用的函数,但它不会让您获得其他数据类型、指向C端数据的指针等等。

4

首先,userdata指的是完整的userdata。以下是两种实现CharArray的解决方案,请参考以下内容:

//full userdata 
extern "C" int newarray(lua_State* L)
{
     int n = luaL_checkint(L, 1);
     size_t nbytes = sizeof(CharArray) + (n - 1)*sizeof(char);
     CharArray* a = (CharArray*)lua_newuserdata(L, nbytes);
     a->size = n;
     return 1;
}

//light userdata 
extern "C" int newlarray(lua_State* L)
{
    int n = luaL_checkint(L, 1);
    size_t nbytes = sizeof(CharArray) + (n - 1)*sizeof(char);
    CharArray* a = (CharArray*)(new char(nbytes));

    lua_pushlightuserdata(L,a);
    a->size = n;

    return 1;
}

完整的 userdata 是一个没有预定义操作的原始内存区域,由 Lua 提供。因此,userdata 必须由垃圾回收器进行管理。 另一方面,轻量级 userdata 只是表示 C 指针(即 void * 值)的值。轻量级 userdata 不需要由垃圾收集器进行管理(也不会被管理)。


3

每当您有一些数据需要由Lua GC管理时,都可以使用userdata。例如,您可以将其用于C ++对象。以下是一些C ++对象与userdata的示例:您可以在userdata中保存一个C ++对象,然后在C ++中忘记它,因为它将由Lua管理。因此,您可以将其引用在Lua变量中,并将其传递给调用C ++对象成员函数的函数。 (当然有方法可以将其泛化,例如将通用函数对象放入userdata中,将其绑定为C闭包的upvalue,并将该C闭包注册到表示C ++对象的Lua对象上,其中也涉及userdata)。 如果您不希望Lua GC管理您的对象,只想从Lua引用您的C ++对象,则可以将指向它的指针存储为轻量级userdata。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接