代码之家  ›  专栏  ›  技术社区  ›  andygeers

从C查询Lua用户数据类型

  •  6
  • andygeers  · 技术社区  · 16 年前

    我有一个具有某种元表类型(例如 "stackoverflow.test" )在C代码中,我希望能够准确地检查它是哪种类型,并且根据结果的不同表现出不同的行为。有好的方便的功能吗(就像 luaL_checkudata ,但如果答案不是您想要的,则不必出错)让我查询用户数据的元表类型名称?如果没有,我想我需要用 lua_getmetatable 但是我有点不清楚如何确定刚刚添加到堆栈中的元表的名称。

    只是为了澄清:我使用的是Lua5.1,LualCheckudata的行为发生了变化。我知道在5.0中,它不习惯出错。

    4 回复  |  直到 16 年前
        1
  •  3
  •   akauppi    16 年前

    你会用 lua_getmetatable lua_equal 用于测试表是否相同。

    在我看来,Lua应该对这种类型的扩展给予更多的支持。到目前为止,Lua/C(++)包装系统确实有责任这样做。

    在我最近做的一个包装中(作为商业项目的一部分),我做了 class::instance(L,index) 获取特定类型的用户数据指针。换句话说,该方法检查它是否是用户数据,以及元表是否正确。如果不是,则返回空值。

    Lua可以帮助所有这一切的方法是,如果元表有一个扩展类型信息的标准字段(S.A. __type )这个可以用来 type() 本身会返回“userdata”,“xxx”(两个值,当前只返回一个)。这将与大多数当前代码保持兼容。但这只是假设(除非您自己执行自定义类型()并实现它)。

        2
  •  5
  •   RBerteig Keith Adler    16 年前

    您可以始终在元表中存储一个标记字段,该字段具有模块独有的light userdata值。

    static const char *green_flavor = "green";
    ...
    void my_setflavor(lua_State *L, void *flavor) {
      lua_pushlightuserdata(L,flavor);
      lua_pushlstring(L,"_flavor");
      lua_rawset(L,-3);
    }
    
    void my_isflavor(lua_State *L, void *flavor) {
      void *p = NULL;
      lua_pushlstring(L,"_flavor");
      lua_rawget(L,-2);
      p = lua_touserdata(L,-1);
      lua_pop(L,1);
      return p == flavor;
    }
    

    然后你可以用 my_setflavor(L,&green_flavor) 在堆栈顶部设置表的风味字段,以及 my_isflavor(L,&red_flavor) 测试堆栈顶部表的风味字段。

    通过这种方式,“口味”字段只能接受在范围内具有“绿色口味”符号的模块中的代码可以创建的值,查找字段并测试其值只需要一个表查找,而不需要检索元表本身。注意,变量green_flavor的值并不重要,因为实际上只使用了它的地址。

    有了几个不同的口味变量可用作句子值,可以使用_flavor字段来区分几个相关的元表。

    所有这些都表明,一个自然的问题是“为什么要这样做?”毕竟,元表可以轻松地包含获得适当行为所需的所有信息。它可以很容易地保存函数和数据,并且可以从C和Lua中检索和调用这些函数。

        3
  •  2
  •   Norman Ramsey    16 年前

    用户数据必须有一个元表,所以抓住它,然后在注册表中查找您想要的名称。如果这两个对象相同,您就找到了要查找的类型。

    您可以在C代码中调度此类型,但请允许我建议您改为指定元表的字段。存储在元表中的函数应该执行该操作,但如果不执行,则必须执行 switch 在C代码中,然后选择一个名称,使用该名称索引到元表中,并为每个元表分配一个可以打开的小整数。

    meta1.decision = 1
    meta2.decision = 2
    meta3.decision = 3
    

    然后在你的C代码中

    if (lua_getmetatable(L, 1)) {
      lua_getfield(L, -1, "decision");
      if (lua_isnumber(L, -1)) {
        switch ((int) lua_tonumber(L, -1)) {
           case 1: ... ; break;
           case 2: ... ; break;
           case 3: ... ; break;
        }
        return 0;
      }
    }
    return luaL_error(L, "Userdata was not one of the expected types");
    
        4
  •  0
  •   andygeers    16 年前

    我刚刚查看了 luaL_checkudata 函数,它基本上使用 lua_getmetatable . 然后,它从注册表中使用 lua_getfield 做一个 lua_rawequal 打电话比较一下。