在上一节中我们可以可以元表中的__call方法,使得表变量可以当成函数来使用,那么在c中,能否也通过元表的这个属性,把函数注册进去呢?
看下如下是怎么实现的?
#include "stdafx.h"
extern "C"
{
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
};
static int average(lua_State *L)
{
int a = lua_tonumber(L, -1);
return 0;
}
int main()
{
lua_State *L = lua_open();
luaopen_base(L);
luaopen_table(L);
luaopen_io(L);
luaopen_string(L);
luaopen_math(L);
luaopen_debug(L);
lua_newtable(L);
lua_pushstring(L, "__call");
lua_pushcfunction(L, average);
lua_rawset(L, -3);
lua_setmetatable(L, -2);
lua_setglobal(L, "qq");
lua_pop(L, 1); //After foo register the methods are still on the stack, remove them.
lua_dofile(L, "a.lua");
lua_close(L);
return 0;
}
这里我们创建了一个表,把average
赋给__call
这个表,表变量变成了方法,在使用lua_setglobal
命名为 qq
,在lua中就能调用这个函数了。
lua的代码如下:
qq(8)
同样的,我们可以进一步的进行扩展,把元表中的__index
也加进去,__tostring
也加进去,这样的话,我们可以通过设置元表,来做很多的事情了。
可以参考下面的源代码,如下:
extern "C"
{
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
};
#define FOO "Foo"
typedef struct Foo {
int x;
int y;
} Foo;
static Foo *toFoo(lua_State *L, int index)
{
Foo *bar = (Foo *)lua_touserdata(L, index);
if (bar == NULL) luaL_typerror(L, index, FOO);
return bar;
}
static Foo *checkFoo(lua_State *L, int index)
{
Foo *bar;
luaL_checktype(L, index, LUA_TUSERDATA);
bar = (Foo *)luaL_checkudata(L, index, FOO);
if (bar == NULL) luaL_typerror(L, index, FOO);
return bar;
}
static Foo *pushFoo(lua_State *L)
{
Foo *bar = (Foo *)lua_newuserdata(L, sizeof(Foo));
luaL_getmetatable(L, FOO);
lua_setmetatable(L, -2);
return bar;
}
static int Foo_new(lua_State *L)
{
int x = luaL_optint(L, 1, 0);
int y = luaL_optint(L, 2, 0);
Foo *bar = pushFoo(L);
bar->x = x;
bar->y = y;
return 1;
}
static int Foo_yourCfunction(lua_State *L)
{
Foo *bar = checkFoo(L, 1);
printf("this is yourCfunction\t");
lua_pushnumber(L, bar->x);
lua_pushnumber(L, bar->y);
return 2;
}
static int Foo_setx(lua_State *L)
{
Foo *bar = checkFoo(L, 1);
bar->x = luaL_checkint(L, 2);
lua_settop(L, 1);
return 1;
}
static int Foo_sety(lua_State *L)
{
Foo *bar = checkFoo(L, 1);
bar->y = luaL_checkint(L, 2);
lua_settop(L, 1);
return 1;
}
static int Foo_add(lua_State *L)
{
Foo *bar1 = checkFoo(L, 1);
Foo *bar2 = checkFoo(L, 2);
Foo *sum = pushFoo(L);
sum->x = bar1->x + bar2->x;
sum->y = bar1->y + bar2->y;
return 1;
}
static int Foo_dot(lua_State *L)
{
Foo *bar1 = checkFoo(L, 1);
Foo *bar2 = checkFoo(L, 2);
lua_pushnumber(L, bar1->x * bar2->x + bar1->y * bar2->y);
return 1;
}
static const luaL_reg Foo_methods[] = {
{ "new", Foo_new },
{ "yourCfunction", Foo_yourCfunction },
{ "setx", Foo_setx },
{ "sety", Foo_sety },
{ "add", Foo_add },
{ "dot", Foo_dot },
{ 0, 0 }
};
static int Foo_gc(lua_State *L)
{
printf("bye, bye, bar = %p\n", toFoo(L, 1));
return 0;
}
static int Foo_tostring(lua_State *L)
{
char buff[32];
sprintf(buff, "%p", toFoo(L, 1));
lua_pushfstring(L, "Foo (%s)", buff);
return 1;
}
static int average(lua_State *L)
{
return 0;
}
static const luaL_reg Foo_meta[] = {
{ "__gc", Foo_gc },
{ "__tostring", Foo_tostring },
{ "__add", Foo_add },
{ "__call", average },
{ 0, 0 }
};
int Foo_register(lua_State *L)
{
luaL_openlib(L, FOO, Foo_methods, 0); /* create methods table,
add it to the globals */
luaL_newmetatable(L, "Foo"); /* create metatable for Foo,
and add it to the Lua registry */
luaL_openlib(L, 0, Foo_meta, 0); /* fill metatable */
lua_pushliteral(L, "__index");
lua_pushvalue(L, -3); /* dup methods table*/
lua_rawset(L, -3); /* metatable.__index = methods */
//lua_pushliteral(L, "__metatable");
//lua_pushvalue(L, -3); /* dup methods table*/
//lua_rawset(L, -3); /* hide metatable:
// metatable.__metatable = methods */
lua_pop(L, 1); /* drop metatable */
return 1; /* return methods on the stack */
}
int main()
{
lua_State *L = lua_open();
luaopen_base(L);
luaopen_table(L);
luaopen_io(L);
luaopen_string(L);
luaopen_math(L);
luaopen_debug(L);
Foo_register(L);
lua_pop(L, 1); //After foo register the methods are still on the stack, remove them.
lua_dofile(L, "a.lua");
lua_close(L);
return 0;
}
lua
中可以这样的来调用:
for n,v in Foo do print(n,v) end
local a = Foo.new()
a()
Foo.setx(a,1)