Lua中的userdata和lightuserdata是什么?

时间:2010-12-01 22:06:05

标签: lua

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

我一直试图绕过它一段时间,但我似乎找不到任何我真正理解的教程/解释。

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

4 个答案:

答案 0 :(得分:49)

userdata是任意大小和内容的垃圾收集值。您可以使用lua_newuserdata()在C API中创建一个,它会在堆栈上创建并推送它,并为您提供指向其内容的指针,以便根据您的需要从C进行初始化。

与调用malloc()非常相似。与malloc()的一个关键区别是你永远不需要调用free(),而只是允许最后一次引用它消失,垃圾收集器最终会回收它的存储。

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

轻量级用户数据是如何在Lua中表示指向某事物的指针。您可以通过使用指针作为其值来调用lua_pushlightuserdata()来创建一个。它们由Lua管理的方式与数字相同。当您需要以可在Lua中传递名称的方式命名C对象时,它们很有用,但对象的生命周期不由Lua管理。类似数字在具有相同值时相等,轻用户数据在保持相同指针时比较相等。与数字一样,只要它们在堆栈中或存储在变量中,它们就存在,并且它们没有单独的元表,也不会被垃圾收集。

答案 1 :(得分:7)

嗯,userdata是来自C端的数据,可以在Lua中使用。例如文件句柄,因为io.input是userdata(尝试print(type(io.input)))。如果你开始搞乱Lua C-API(或者使用newproxy函数,它会给你一个空的userdatum,你可以在其上设置metatable(参见隐藏的功能http://lua-users.org/wiki/HiddenFeatures),你自己就需要它了。 Lua-users wiki)。

一个很好的介绍是: http://www.lua.org/pil/28.html

至于C函数:你可以将C函数注册为从Lua中调用的函数,但是它不会得到其他数据类型,指向C端数据的指针等等。

答案 2 :(得分:2)

你可以使用userdata每当你想要的数据量由lua gc管理时。例如,您可以将它用于C ++对象。 c ++的一些例子 - 带有userdata的对象:你可以在userdata中保存一个,然后你可以在C ++中忘记它,因为它将由lua管理。所以你可以在luavariables中引用它并将它传递给调用c ++对象的成员函数的函数。 (有一些方法可以概括当然就像将泛型函数对象放在userdata中,将其作为upvalue绑定到C-closure并在表示c ++对象的lua-side的luaobject上注册c-closure,这涉及到userdata也是)。 如果您不希望lua gc管理您的对象并且只想从lua引用您的c ++对象,则可以将指针存储为轻用户数据。

答案 3 :(得分:2)

首先,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;
}

完整用户数据是一个原始内存区域,没有预定义的操作,它来自Lua 。因此userdata必须由垃圾收集器管理。 另一方面,light userdata只是表示C指针的值(即void *值)。 Light userdata不需要由垃圾收集器管理(并且不是)。