Ich versuche Lua Bindungen zu schreiben, so dass man beliebige Funktionen auf einem userdata aufrufen kann. Ein MCV-Beispiel, an dem ich gearbeitet habe, ist unten.Lua: Aufruf von __index Funktion funktioniert dann löst Fehler
Zusammenfassend: Wir haben die C-Funktion newarray
an eine Tabelle in der Lua globals geschoben, so dass man ein neues Array-Objekt erstellen kann. Angenommen, das Array ist ein Datenbankeintrag. Ich habe zwei Arten von Operationen, die ich ausführen möchte, nachdem ich sie mit newarray
erzeugt habe (für dieses schlechte Beispiel): auf ein Element zugreifen und das Objekt zerstören.
Da ich nicht weiß, wie viele Elemente es gibt (in einem realen Beispiel), entscheide ich mich, __index
eine Funktion zu machen und eine if-Anweisung zu verwenden, um zu bestimmen, ob die Funktion "destroy" war oder irgendetwas anderes (dh "gib mir dieses Element"). Wenn es "zerstören" war, lösche das Objekt; Andernfalls geben Sie das angeforderte Element zurück.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#define TEST_METATABLE "_test_mt"
typedef struct
{
int* array;
} array_t;
int newArray(lua_State* L)
{
assert(lua_gettop(L) == 0);
array_t* array = lua_newuserdata(L, sizeof(array_t));
array->array = malloc(sizeof(int) * 10);
for (int i = 0; i < 10; i++)
array->array[i] = i;
/* Set metatable */
lua_getfield(L, LUA_REGISTRYINDEX, TEST_METATABLE);
lua_setmetatable(L, -2);
return 1;
}
int indexFunc(lua_State* L)
{
int argc = lua_gettop(L);
array_t* array = luaL_checkudata(L, 1, TEST_METATABLE);
const char* key = luaL_checkstring(L, 2);
int ret = 0;
if (!strcmp(key, "destroy"))
{
if (argc != 2)
{
lua_settop(L, 0);
luaL_error(L, "Invalid arguments");
}
if (array->array)
{
free(array->array);
array->array = NULL;
}
printf("Finished destroy\n");
lua_settop(L, 0);
}
else
{
if (argc != 2)
{
lua_settop(L, 0);
luaL_error(L, "Invalid arguments");
}
if (lua_tointeger(L, 2))
{
lua_pushinteger(L, array->array[lua_tointeger(L, 2)]);
}
else
{
lua_settop(L, 0);
luaL_error(L, "Bad index supplied");
}
lua_remove(L, 2);
lua_remove(L, 1);
ret = 1;
}
return ret;
}
int luaopen_TestArray(lua_State* L)
{
/* Set up metatable */
lua_newtable(L);
lua_pushliteral(L, "__index");
lua_pushcfunction(L, indexFunc);
lua_settable(L, -3);
lua_setfield(L, LUA_REGISTRYINDEX, TEST_METATABLE);
/* Set up 'static' stuff */
lua_newtable(L);
lua_pushliteral(L, "newarray");
lua_pushcfunction(L, newArray);
lua_settable(L, -3);
lua_setglobal(L, "TestArray");
return 0;
}
ich mit kompiliert:
gcc -std=c99 -Wall -fPIC -shared -o TestArray.so test.c -llua
Der Lua-Testprogramm wird wie folgt:
require("TestArray")
a = TestArray.newarray()
print(a[5])
a:destroy()
Der Ausgang:
$ lua test.lua
5
Finished destroy
lua: test.lua:7: attempt to call method 'destroy' (a nil value)
stack traceback:
test.lua:7: in main chunk
[C]: ?
$
Das Gleiche gilt für Lua, was es soll durch Abrufen des v alue (in Bezug auf C) und Drucken es (wie es sicherlich durch indexFunc
). Dann fährt es fort, den destroy-spezifischen Code in indexFunc
, auszuführen, dann versucht nach einer Funktion zu suchen, die destroy
genannt wird, und ich habe keine Idee warum. Es hat das 0metamethod __index
gefunden, also verstehe ich nicht, warum es an anderer Stelle danach aussah. Warum tut es das und was mache ich falsch?
Lua-Version: 5.1.4.
'__index' metamethod sollte nur den Wert für den Schlüssel" destroy "abrufen, das heißt," indexFunc "muss nur einen Wert zurückgeben (Funktion" destroy "), ohne diese Funktion auszuführen. Destruktor sollte als separate Funktion 'int destroyFunc (lua_State * L)' implementiert werden. Schnelle Lösung: Ersetzen Sie einfach 'a: destroy()' durch 'local _ = a.destroy' :-) –
@EgorSriptounoff Ohh, ich verstehe, also liegt es an den Klammern nach 'destroy', die im Grunde bedeuten:" rufen Sie das Ergebnis von "zerstören" als eine Funktion abrufen "? Wenn Sie es als Antwort einreichen möchten, werde ich akzeptieren, weil AFAIK Sie nicht einen verdienten Ruf von einem Kommentar erhalten. :) – Doddy