【问题标题】:What is userdata and lightuserdata in Lua?Lua 中的 userdata 和 lightuserdata 是什么?
【发布时间】:2011-05-18 19:06:27
【问题描述】:
  • 什么是 Lua 中的 userdata 和 lightuserdata?
  • 我在哪里需要它?

我一直在努力思考它一段时间,但我似乎找不到任何我真正理解的教程/解释。

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

【问题讨论】:

  • 元表必须附加到 something,用户数据是一个合理的选择。

标签: lua


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

    好吧,userdata 是来自 C 端的数据,可以在 Lua 中使用。例如 io.input 的文件句柄是用户数据(尝试 print(type(io.input)))。如果你开始弄乱 Lua C-API(或使用 newproxy 函数,它会给你一个空的用户数据,你可以在 Lua 上设置一个元表(参见隐藏功能http://lua-users.org/wiki/HiddenFeatures)用户维基)。

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

    至于 C 函数的东西:是的,您可以将 C 函数注册为要从 Lua 中调用的函数,但它不会为您提供其他数据类型、指向 C 端数据的指针等。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        首先,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 只是一个表示 C 指针的值(即 void * 值)。轻量级用户数据不需要由垃圾收集器管理(现在也不是)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-02-20
          • 2013-12-07
          • 1970-01-01
          • 1970-01-01
          • 2010-11-19
          • 2019-08-02
          • 2018-02-16
          • 2011-02-25
          相关资源
          最近更新 更多