【发布时间】:2016-07-09 23:10:59
【问题描述】:
我正在尝试编写 Lua 绑定,以便可以在用户数据上调用任意函数。下面是我一直在研究的一个 MCV 示例。
总而言之:我们将 C 函数 newarray 推送到 Lua 全局变量中的一个表中,这样就可以创建一个新的数组对象。假设数组是一个数据库记录。在使用newarray 生成它之后,我有两种操作要对其执行(对于这个不好的例子):访问元素和销毁对象。
由于我不知道会有多少元素(在现实世界的示例中),我决定将__index 设为一个函数并使用 if 语句来确定该函数是“销毁”还是其他什么(即“给我这个元素”)。如果是“destroy”,则删除该对象;否则,返回请求的元素。
#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;
}
我编译的是:
gcc -std=c99 -Wall -fPIC -shared -o TestArray.so test.c -llua
Lua测试程序如下:
require("TestArray")
a = TestArray.newarray()
print(a[5])
a:destroy()
输出:
$ 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]: ?
$
所以 Lua 通过检索第 6 个元素的值(以 C 表示)并打印它(通过indexFunc 肯定会这样做)来完成它应该做的事情。然后它继续执行indexFunc 中的特定于销毁的代码,然后 试图寻找一个名为destroy 的函数,我不知道为什么。它找到了__index 元方法,所以我不明白为什么它后来在别处寻找。为什么会这样,我做错了什么?
Lua 版本:5.1.4。
【问题讨论】:
-
__index元方法应该只检索键“destroy”的值,也就是说,indexFunc必须只返回一个值(函数“destroy”)而不执行此函数。析构函数应该实现为单独的函数int destroyFunc(lua_State* L)。快速解决方案:只需将a:destroy()替换为local _ = a.destroy:-) -
@EgorSkriptunoff 哦,我明白了,所以这是因为
destroy后面的括号基本上意味着“调用检索'destroy'作为函数的结果”?如果您想将其作为答案提交,我会接受,因为 AFAIK 您不会从评论中获得任何当之无愧的代表。 :)
标签: lua