来自c问题的lua metatable注册

时间:2011-02-23 13:52:37

标签: lua

您好我有以下一些代码似乎可行,但我不知道为什么 - 我已经构建了一个如下的测试类

class testclass {
    int ivalue;
public:
    int getivalue();
    void setivalue(int &v);
};

然后注册了testclass(为实际功能留出的位,但它们非常基本)。这是我不遵循的元表的注册。 (etivalue和setivalue是调用同名类函数的c函数)

static const struct luaL_Reg arraylib_f [] = {
    {"new", new_testclass},
    {NULL, NULL}
};

static const struct luaL_Reg arraylib_m [] = {
    {"set", setivalue},
    {"get", getivalue},
    {NULL, NULL}
};

int luaopen_testclass (lua_State *L) {
    luaL_newmetatable(L, "LuaBook.testclass");
    lua_pushvalue(L, -1); /* duplicates the metatable */
    lua_setfield(L, -2, "__index");
    luaL_register(L, NULL, arraylib_m);
    luaL_register(L, "testclass", arraylib_f);
    return 1;
}

我不明白的是我正在将函数添加到metatable的__index中 我跑的时候

a = testclass.new()
a:set(10)
print(a:get())

然后按预期工作。我不明白的是为什么在我认为我已经将它加载到__index metatable时调用该集合?那是我做过的还是别的什么?

TIA

2 个答案:

答案 0 :(得分:4)

int luaopen_testclass (lua_State *L) {
    luaL_newmetatable(L, "LuaBook.testclass"); //leaves new metatable on the stack
    lua_pushvalue(L, -1); // there are two 'copies' of the metatable on the stack
    lua_setfield(L, -2, "__index"); // pop one of those copies and assign it to
                                    // __index field od the 1st metatable
    luaL_register(L, NULL, arraylib_m); // register functions in the metatable
    luaL_register(L, "testclass", arraylib_f);
    return 1;
}

该代码等同于示例Lua代码:

metatable = {}
metatable.__index = metatable
metatable.set = function() --[[ stuff --]] end
metatable.get = function() --[[ stuff --]] end

我假设'new_testclass'C函数为返回的表设置元表“LuaBook.testclass”。

在您的代码中,您不会向metatable __index字段添加函数。将指向metatable的指针分配给名为__index的metatable的字段,并向其注册set和get函数。

现在,如果你将metatable设置为'new_testclass'函数返回的值(我假设你这样做) - 让我们调用那个值'foo',你调用foo:set(10),而不是Lua:

  1. 检查'foo'
  2. 中是否存在'set'字段
  3. 看到'foo'有一个metatable
  4. 查看metatable的__index字段 - 看它是一张表
  5. 检查分配给__index字段的表是否有字段'set'且它的值是函数
  6. 调用'set'方法将'foo'作为自身参数传递
  7. 我希望这可以帮助你弄清楚这里发生了什么。

答案 1 :(得分:1)

如果我理解了您的问题,那么您就会问set() get()如何通过__index元方法调用。

代码可以用纯lua表示:

local o = {}

function o.get(self)
    return self.ivalue
end

function o.set(self, val)
    self.ivalue = val
end

a = {}
mt = {
    __index = function(t, n)
        return o[n]
    end
}

setmetatable(a, mt)

print(a:get())
a:set(10)
print(a:get())

结果:

nil
10

在此示例中,mt表被设置为a表的metatable。 __indexget同时调用set元方法,因为表get中当前不存在seta

如果更改此示例而不是:

local o = {}

function o.get(self)
    return self.ivalue
end

function o.set(self, val)
    self.ivalue = val
end

a = {}

function a.get(self)
    print('here')
    return self.ivalue
end

mt = {
    __index = function(t, n)
        return o[n]
    end
}

setmetatable(a, mt)

print(a:get())
a:set(10)
print(a:get())

结果:

here
nil
here
10

在这种情况下,__index元方法为get()调用 NOT ,因为get表中已存在a索引。

一旦您了解了它们的工作原理,就可以使用元方法创建许多有趣的构造。我建议阅读13.4.1 - The __index Metamethod in PiL并再做一些例子。以上所有内容也可以从 c api 完成。