lua metatable регистрация от c вопрос - PullRequest
1 голос
/ 23 февраля 2011

Здравствуйте, у меня есть следующий фрагмент кода, который, кажется, работает, но я не уверен, почему - я построил тестовый класс следующим образом

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

, а затем зарегистрировал тестовый класс (биты пропущены)для реальных функций, но они довольно простые).Я не слежу за регистрацией метатаблиц.(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;
}

Немного не понимаю, что я добавляю функции в __index для метатаблицы, но когда я запускаю

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

Тогда все работает как положено.Но я не понимаю, почему этот набор вызывается, когда я думаю, что загрузил его в метатаблицу __index?Это то, что я сделал или что-то еще?

tia

Ответы [ 2 ]

4 голосов
/ 23 февраля 2011
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

Я предполагаю, что функция C 'new_testclass' устанавливает метатабельный "LuaBook.testclass" для возвращаемой таблицы.

В вашем коде вы не добавляете функции к метатабельному полю __index. Вы присваиваете указатель метатаблице для поля метатаблицы с именем __index, и вы регистрируете set и получаете функции для него.

Теперь, если вы установите для этого метатабора значение, возвращаемое функцией 'new_testclass' (что, как я полагаю, вы делаете), - давайте вызовем это значение 'foo', и вы вызовете foo: set (10), чем Lua:

  1. проверяет, что в 'foo' нет такого поля как 'set'
  2. видит, что у 'foo' есть метатабель
  3. смотрит на поле __index метатаблицы - видит, что это таблица
  4. проверяет, имеет ли таблица, назначенная полю __index, поле 'set' и является ли она функцией
  5. вызывает метод 'set', передавая 'foo' в качестве собственного параметра

Я надеюсь, что это поможет вам понять, что здесь происходит.

1 голос
/ 23 февраля 2011

Если я понимаю ваш вопрос, вы спрашиваете, как 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.Метаметод __index вызывается как для get, так и для set, поскольку в настоящее время в таблице a.

нет ни get, ни set. Если этот пример заменен на этот:

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 имеет значение NOT , вызванное для get(), поскольку индекс get уже существует в a таблица.

Многие интересные конструкции могут быть созданы с использованием метаметодов, как только вы поймете, как они работают.Я предлагаю прочитать 13.4.1 - Метаметод __index в PiL и проработать еще несколько примеров.Все вышеперечисленное также можно сделать из c api .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...