开发者

lua metatable registration from c question

开发者 https://www.devze.com 2023-02-12 17:11 出处:网络
Hello I have the following bit of code which seems to work, but I\'m not sure why - I\'ve built a testclass as follows

Hello I have the following bit of code which seems to work, but I'm not sure why - I've built a testclass as follows

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

and then registered the testclass (bits left out for the actual functions but they're pretty basic). It's the registration of the metatables I'm not following. (etivalue and setivalue are c functions that call the class functions of the same name)

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

static const struct luaL_Reg arraylib_m [] = {
    {"set", setivalue},
    {"get", geti开发者_StackOverflow中文版value},
    {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;
}

The bit I don't understand is I'm adding the functions to the __index for the metatable but when I run

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

Then it works as expected. The bit I don't understand is why the set is being called when I think I've loaded it in the __index metatable? Is that what I've done or something else?

tia


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;
}

That code is equivalent to the example Lua code:

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

I assume that 'new_testclass' C function sets the metatable "LuaBook.testclass" for the returned table.

In your code you dont add functions to the metatable __index field. You assign pointer to metatable to that metatable's field named __index, and you register set and get functions to it.

Now, if you set that metatable to the value returned from 'new_testclass' function (which I assume you do) - lets call that value 'foo', and you call foo:set(10), than Lua:

  1. checks that there is no such field as 'set' in 'foo'
  2. sees that 'foo' has a metatable
  3. looks at that metatable's __index field - sees it's a table
  4. checks if that table assigned to __index field has a field 'set' and it's value is a function
  5. calls 'set' method passing 'foo' as self parameter

I hope that this will help you figure out whats going on here.


If I understand your question, you are asking how the set() get() get invoked through the __index metamethod.

The code can be expressed in pure 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())

results:

nil
10

In this example the mt table is set as the a table's metatable. The __index metamethod is invoked for both get and set since neither get or set currently exist in table a.

If this example is changed instead to this:

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())

results:

here
nil
here
10

In this case the __index metamethod is NOT invoked for get() since a get index already exists in the a table.

Many interesting constructs can be created using metamethods, once you understand how they work. I suggest reading 13.4.1 - The __index Metamethod in PiL and work through a few more examples. All of the above can also be done from the c api.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号