我有一個使用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