ルアでは、関数ポインタと、クロージャが呼び出されたときに使用可能な追加の値(upvalues)を使用してC closureが作成されます。テールコールでLua関数クロージャを残すにはどうしたらいいですか?
私のアプリケーションでは、ゲッターメソッドテーブルを__index
メタメソッドに渡すためにこの機能を使用します。メソッドとしてキーが存在する場合、キーは元のパラメータを渡して呼び出されます。関数を直接呼び出すと、何らかの形でアップルの値が呼び出され、同じ関数クロージャで実行されます。
関数クロージャを終了するか、何らかの理由でアップルを消去することはできますか?目標は、重大なオーバーヘッドを招くことなく、上昇値の不必要な露出を減らすことです。
MWD(42行)は、この問題を強調表示するTODOの問題を示しています。現在、upvalue: 42
が2回印刷されています。期待される結果は、1つのupvalue: 42
ともう1つの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);
}
これは単純に新しいクロージャを作成しませんか?戻り値はどうですか(これはコンパイル時に 'lua_call'が無効です)。私の場合、おそらく常に0または1つの戻り値があることを確かめることができますが、これを一般化することはできますか? (スタックによる引数の保存に関する更新された要件も参照してください) – Lekensteyn
@Lekensteyn戻り値のために更新されました。この例では、同じ引数を使用したくないと思います。それは、関数自体を意味のないものに渡すだけなので、私は考えています。 – immibis
ありがとうございますが、私は実際に元のパラメータを渡したいと思います。実際には、私は 'metatable .__ newindex(obj、key、value)'を持っているので、setter(obj、value)を呼び出すべきです。 'lua_gettop(L)'前/後の提案は返された値を見つけるのは良いですが、 'lua_call(0、lua_gettop(L)、LUA_MULTRET)')を保持するように変更した場合、 lapi.c:895:lua_callk:Assertion '((nargs + 1)< (L-> top-L-> ci-> func))&& "スタックの要素が不足しています。何か案が? – Lekensteyn