如何让Lua迭代器返回一个C结构体?

我有一个使用 Lua 5.2.1 的 Visual Studio 2008 C++03 项目,我想让迭代器返回一个对象,这样我就可以获取参数值或调用相关函数。

例如:

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' :对错误的 self 调用'bar'。

我意识到有包装器可以做到这一点,但在实现任何包装器之前,我更愿意了解底层的 Lua 机制。

点赞