我有一个使用Lua 5.2.1的Visual Studio 2008 C++ 03项目,我希望有一个迭代器返回一个对象,以便我可以获取参数值或调用相关函数。 例如:如何让Lua迭代器返回一个C结构?
for f in foo.list() do
if f:bar() then
print("success")
else
print("failed")
end
print(string.format("%d: %s", f.id, f.name))
end
我使用下面的C++代码来实现这个(错误检查省略):
struct Foo {
int id;
char name[ 256 ];
HANDLE foo_handle;
}
int foo_list(lua_State* L)
{
Foo* f = (Foo*)lua_newuserdata(L, sizeof(Foo));
ZeroMemory(f, sizeof(Foo));
luaL_getmetatable(L, foo_metatable);
lua_setmetatable(L, -2);
f->foo_handle = CreateFooHandle();
lua_pushcclosure(L, foo_iter, 1);
return 1;
}
int foo_iter(lua_State* L)
{
Foo* foo = (Foo*)lua_touserdata(L, lua_upvalueindex(1));
if(GetNextFoo(foo)) /*sets the id and name parameters*/
{
// is this correct? I need to return some object...
luaL_getmetatable(L, foo_metatable);
return 1;
}
return 0;
}
int foo_name(lua_State* L)
{
Foo* f = (Foo*)luaL_checkudata(L, 1, foo_metatable);
lua_pushstring(L, f->name);
return 1;
}
int foo_id(lua_State* L)
{
Foo* f = (Foo*)luaL_checkudata(L, 1, foo_metatable);
lua_pushinteger(L, f->id);
return 1;
}
int foo_bar(lua_State* L)
{
Foo* f = (Foo*)luaL_checkudata(L, 1, foo_metatable);
if(FooBar(f))
lua_pushboolean(L, true);
else
lua_pushboolean(L, false);
return 1;
}
int foo_close(lua_State* L) { /*omitted. this part works*/ }
extern "C" int luaopen_foo(lua_State* L)
{
// how do I differentiate between a parameter get and a function call?
const luaL_Reg foo_methods[] = {
{ "name", foo_name },
{ "id", foo_id },
{ "bar", foo_bar },
{ "__gc", foo_close },
{ NULL, NULL }
};
luaL_newmetatable(L, foo_metatable);
luaL_setfuncs(L, foo_methods, 0);
const luaL_Reg foo[] = {
{ "list", foo_list }
{ NULL, NULL }
};
luaL_newlib(L, foo);
return 1;
}
但是,当我运行它,我得到的Lua错误:foo.lua:2: calling 'bar' on bad self
我意识到有包装可能会这样做,但我更愿意在实现任何包装之前了解基础Lua机制。
在' foo_list'我将metatable设置为成为Foo的一个实例。为什么这不是我想要返回的?如果这不是我想要回报的那么那是什么? – PaulH
是的,但在你的ITER功能你不回该实例,你只返回元表。 – Mud
什么的'-2'在线路'lua_setmetatable(L -2,);'指向在堆栈上? lua_newuserdata()? – PaulH