Как создать таблицу в таблице в Lua 5.1, используя C-API?
Мне нужно создать такую конструкцию в Lua 5.1 C-API, а не в Lua 5.2 и выше
a = {["b"] = {["c"] = {["d"] = {["e"] = "GOOD"}}}}
print(a.b.c.d.e);
Ожидаемый результат: ХОРОШО
Спасибо за ответы!
1 ответ
Lua C API основан на стеке. Это означает, что поведение большинства функций C API зависит не только от заданных аргументов, но и от содержимого стека Lua (который является частью lua_State*
переменная обычно называется L
). Что ожидает конкретная функция API в отношении содержимого стека и как оно влияет на элементы стека, вам нужно будет посмотреть в руководстве по Lua.
Давайте начнем с создания таблицы и присвоения ее глобальной переменной a
:
lua_newtable( L );
lua_setglobal( L, "a" );
Это эквивалентно фрагменту кода Lua: a = {}
,
Документация для lua_newtable()
говорит нам, что функция помещает новую таблицу в верхнюю часть стека Lua. Это хорошо вписывается в lua_setglobal()
, который извлекает значение из вершины стека и присваивает его глобальной переменной с заданным именем. Таким образом, обе функции вместе (как в приведенном выше фрагменте) сбалансированы с точки зрения эффектов стека. Хорошая особенность кусочков кода, сбалансированных по стеку, заключается в том, что вы можете вставлять их в любое место, и объединенный код все еще действителен. (Общее правило: вы можете заменить один оператор на ряд операторов, и наоборот, если (комбинированные) эффекты стека одинаковы.) Например:
lua_newtable( L ); /* ==> stack: ..., {} */
lua_pushnil( L ); /* ==> stack: ..., {}, nil */
lua_pop( L, 1 ); /* ==> stack: ..., {} */
lua_setglobal( L, "a" ); /* ==> stack: ... */
будет по-прежнему назначать таблицу глобальной переменной a
так как lua_pushnil( L );
а также lua_pop( L, 1 );
вместе не меняйте содержимое стека Lua. Вместо этого бесполезного нажатия / добавления мы добавим код, который изменяет таблицу после того, как она помещена в стек, и до того, как она будет удалена из стека и назначена глобальной переменной. Как я уже сказал, вы можете вставлять сбалансированные по стеку фрагменты кода в любое место между двумя функциями Lua C API, поэтому вам просто нужно определить правильное место, где в стеке содержатся все необходимые вам элементы.
Мы хотим добавить поле в таблицу с ключом "b"
и другая таблица в качестве значения. Функция Lua C API для этого lua_settable()
(есть другие вспомогательные функции, которые работают только для определенных типов клавиш, например, lua_setfield()
, но мы пойдем с lua_settable()
Вот). lua_settable()
нужна таблица для хранения пары ключ / значение где- нибудь в стеке Lua (что обычно означает, что вы должны передать индекс стека в качестве аргумента), а также ключ и значение в качестве двух самых верхних элементов на стек. Ключ и значение (но не таблица) будут отображаться lua_settable()
:
lua_newtable( L ); /* ==> stack: ..., {} */
lua_pushliteral( L, "b" ); /* ==> stack: ..., {}, "b" */
lua_newtable( L ); /* ==> stack: ..., {}, "b", {} */
lua_settable( L, -3 ); /* ==> stack: ..., {} */
lua_setglobal( L, "a" ); /* ==> stack: ... */
Эквивалентный код Lua будет a = { b = {} }
Зачастую вас не волнует, что находится ниже определенной точки стека Lua, и вот где индексы относительно вершины стека (-3
в приведенном выше фрагменте кода) вступите в игру. -3
относится к таблице, которая находится чуть ниже ключа "b"
(который находится в -2
) и ниже другой таблицы (которая находится на вершине стека в -1
).
Вы, вероятно, уже увидите, куда это идет: теперь мы хотим изменить новую таблицу, поэтому мы добавляем сбалансированный по стеку код в нужном месте (после того, как новая таблица помещена в стек). Я пропущу несколько шагов и укажу, куда я вставил код с отступом:
lua_newtable( L ); /* ==> stack: ..., {} */
{
lua_pushliteral( L, "b" ); /* ==> stack: ..., {}, "b" */
lua_newtable( L ); /* ==> stack: ..., {}, "b", {} */
{
lua_pushliteral( L, "c" ); /* == stack: ..., {}, "b", {}, "c" */
lua_newtable( L ); /* ==> stack: ..., {}, "b", {}, "c", {} */
{
lua_pushliteral( L, "d" );
lua_newtable( L );
{
lua_pushliteral( L, "e" );
lua_pushliteral( L, "GOOD" );
lua_settable( L, -3 );
}
lua_settable( L, -3 );
}
lua_settable( L, -3 ); */ ==> stack: ..., {}, "b", {} */
}
lua_settable( L, -3 ); /* ==> stack: ..., {} */
}
lua_setglobal( L, "a" ); /* ==> stack: ... */
Когда вы разрабатываете код со сложными манипуляциями со стеком, это часто помогает распечатать текущее содержимое стека в ключевых точках или, по крайней мере, проверить, сколько элементов в стеке (см. lua_gettop()
) это то, что вы ожидаете. Вот что я использую для этого.