В Lua создается C closure с указателем функции и дополнительными значениями (upvalues ), которые будут доступны при вызове закрытия.Как я могу оставить закрытие функции Lua в хвостовом вызове?
В моем приложении я использую эту функцию, чтобы передать таблицу методов геттера методу __index
. Если ключ существует как метод, он будет вызываться, передавая его исходные параметры. Если я вызываю функцию напрямую, то как-то выше значения все еще доступны для вызываемого абонента и, таким образом, выполняются при одном и том же закрытии функции.
Можно ли оставить функцию закрытия или каким-либо образом стереть верхние значения? Цель состоит в том, чтобы уменьшить ненужное воздействие повышений без существенных накладных расходов.
Это MWE (42 строки), который демонстрирует проблему с TODO, подчеркивающим проблему. В настоящее время он печатает upvalue: 42
дважды. Ожидаемый результат - один upvalue: 42
и еще один upvalue: 0
(за недопустимое значение).
#include <stdlib.h>
#include <stdio.h>
#include <lua.h>
static void *allocfn(void *ud, void *ptr, size_t osize, size_t nsize) {
if (nsize == 0) {
free(ptr);
return NULL;
} else {
return realloc(ptr, nsize);
}
}
static int myfunc(lua_State *L) {
lua_CFunction cfunc = lua_tocfunction(L, 1);
printf("myfunc called with %p\n", cfunc);
printf("upvalue: %d\n", (int)lua_tointeger(L, lua_upvalueindex(1)));
// TODO how to drop upvalue (tail call, leaving the closure)?
return cfunc(L);
}
static int otherfunc(lua_State *L) {
printf("otherfunc called with %p\n", lua_tocfunction(L, 1));
printf("upvalue: %d\n", (int)lua_tointeger(L, lua_upvalueindex(1)));
return 0;
}
int main() {
lua_State *L = lua_newstate(allocfn, NULL);
/* Create closure for myfunc with upvalue 42. */
lua_pushinteger(L, 42);
lua_pushcclosure(L, myfunc, 1);
/* Argument 1 for myfunc. */
lua_pushcclosure(L, otherfunc, 0);
/* Invoke myfunc(otherfunc) with "42" in its closure. */
lua_call(L, 1, 0);
lua_close(L);
}
Разве это не просто создаст новое закрытие? Как насчет возвращаемых значений (это компилирует btw, 'lua_call' является недействительным). В моем случае я, вероятно, могу быть уверен, что всегда есть нулевые или одно возвращаемые значения, но может ли это быть обобщено? (См. Также обновленные требования по сохранению аргументов через стек) – Lekensteyn
@Lekensteyn Обновлено для возвращаемых значений; Я бы предположил, что в этом примере вы не хотите использовать те же аргументы, поскольку это просто передаст функцию себе, что бессмысленно. – immibis
Спасибо, но я действительно хочу передать исходные параметры. В реальном случае у меня есть 'metatable .__ newindex (obj, key, value)', он должен вызывать 'setter (obj, value)', где 'setter' находится через upvalue. Предложение 'lua_gettop (L)' before/after полезно найти возвращаемые значения, но если я изменю его, чтобы сохранить params ('lua_call (0, lua_gettop (L), LUA_MULTRET)'), то он выдает ошибку: lapi.c: 895: lua_callk: Assertion '((nargs + 1) < (L-> top - L-> ci-> func)) && "недостаточно элементов в стеке"' failed '. Есть идеи? – Lekensteyn