我一直试图绕过它一段时间,但我似乎找不到任何我真正理解的教程/解释。
为什么你需要它们,为什么不能直接将C函数绑定到Lua metatables?
答案 0 :(得分:49)
userdata是任意大小和内容的垃圾收集值。您可以使用lua_newuserdata()
在C API中创建一个,它会在堆栈上创建并推送它,并为您提供指向其内容的指针,以便根据您的需要从C进行初始化。
与调用malloc()
非常相似。与malloc()
的一个关键区别是你永远不需要调用free()
,而只是允许最后一次引用它消失,垃圾收集器最终会回收它的存储。
它们对于保存从C中有用但必须从Lua管理的数据非常有用。它们支持单个元表,这是允许将C或C ++对象绑定到Lua的关键特性。您只需使用C编写的方法填充其元表,该方法访问,修改和/或使用userdata的内容,结果是可从Lua访问的对象。一个很好的例子是io
library,它在userdata中存储C FILE *
指针,并提供实现熟悉的read
,write
和类似方法的绑定。通过实施__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不需要由垃圾收集器管理(并且不是)。