对于lua与C程序相互调用时,如果有一个数字需要在C程序和lua脚本同时使用,这时就需要保持lua程序与C程序中的数字变量一致,及当C程序改变了这个数字变量时lua能够获取改变后的值,当lua程序改变了变量时C程序也可以获取改变后的值。实现这个功能可以给lua变量设置get/set方法。当lua中读取数字变量的值时,则调用对应得get方法,get方法中可以调用C程序中的一个get获取到C程序中数字变量的值,同理给数字变量赋值时也一样。这样lua中使用的数字变量的值就是C程序中的变量值,从而保持一直。
Lua本身并没有提供get/set类的方法,但可以通过环境表元表的__index和__newindex方法实现。当获取一个global变量时,实际上是通过变量名为索引从环境表中获取值,如果环境表中没有变量时会去调用相应的__index方法。所以要实现get/set方法可以将变量存于另一个表,在环境表中不保存相应的变量,在环境表的__index方法中根据变量去查找并调用相应的get/set方法。具体实现如下。
function attr_setup()
local handlers = {} --存储get和set方法
local values = {} --存储值
local mt = {
__index = function(t, k)
local h = handlers[k]
print("get", k)
return h and h.get()
end,
__newindex = function(t, k, v)
local h = handlers[k]
print("set", k)
if h then
return h.set(v)
else
values[k] = v
handlers[k] = {set = function(v) values[k] = v end,
get = function() return values[k] end}
end
end,
}
setmetatable(getfenv(), mt)--将当前环境的元表设为 mt,getfenv()只使用于lua5.1以前的版本,5.2以后请使用_ENV 变量
end
attr_setup()
print(c) -->nil
print(type(c), "\n\n") -->nil
a = 15
print(a) -->15
print(type(a), "\n\n")--number
b = { x = 10};
print(b.x) -->10
print(type(b), "\n\n")-->table
print("rawget(_G, \'b\')", rawget(_G, 'b')) -->nil
#include
extern "C" {
#include "lua\lua.h"
#include "lua\lualib.h"
#include "lua\lauxlib.h"
}
using namespace std;
const char *HandlesGetSet = "HandlesGetSet";
double a = 166;
int a_get(lua_State*L)
{
lua_pushnumber(L, a);
return 1;
}
int a_set(lua_State *L)
{
if (lua_isnumber(L, 1))
{
a = lua_tonumber(L, 1);
}
return 0;
}
int index_event(lua_State*L)
{
//从 registry 中获取变量的get set 方法
luaL_getmetatable(L, HandlesGetSet);
lua_pushvalue(L, 2);
lua_rawget(L, -2);
if (lua_isnil(L, -1))// 没有get set方法
{
lua_pop(L, 2);
lua_rawget(L, -2);
}
else
{
lua_pushstring(L, "get");
lua_rawget(L, -2);
lua_pcall(L, 0, 1, 0);//调用get方法
}
return 1;
}
int newindex_event(lua_State *L)
{
//从 registry 中获取变量的get set 方法
luaL_getmetatable(L, HandlesGetSet);
lua_pushvalue(L, 2);
lua_rawget(L, -2);
if (lua_isnil(L, -1))// 没有get set方法
{
lua_pop(L, 2);
lua_rawset(L, -3);
}
else
{
lua_pushstring(L, "set");//调用set方法
lua_rawget(L, -2);
lua_pushvalue(L, 3);
lua_pcall(L, 1, 0, 0);
}
return 0;
}
int main()
{
lua_State *L = luaL_newstate();
luaL_openlibs(L);
//获取 _G表
#if defined (LUA_VERSION_NUM) && LUA_VERSION_NUM >= 502 /* after lua 5.2 */
lua_pushvalue(L, LUA_REGISTRYINDEX); /* registry */
lua_pushnumber(L, LUA_RIDX_GLOBALS); /* registry globalsindex */
lua_rawget(L, -2); /* registry registry[globalsindex] */
lua_remove(L, -2); /* registry */
#else
lua_pushvalue(L, LUA_GLOBALSINDEX);
#endif
//创建 _G表的元表
lua_newtable(L);
lua_pushstring(L, "__index");
lua_pushcfunction(L, index_event);
lua_rawset(L, -3);
lua_pushstring(L, "__newindex");
lua_pushcfunction(L, newindex_event);
lua_rawset(L, -3);
lua_setmetatable(L, -2);//设置 _G表的元表
lua_pop(L, 1);
//创建一张表存储在 registry 中
luaL_newmetatable(L, HandlesGetSet);
//注册 a 变量的get set方法
lua_pushstring(L, "a");
lua_newtable(L);
lua_pushstring(L, "get");
lua_pushcfunction(L, a_get);
lua_rawset(L, -3);
lua_pushstring(L, "set");
lua_pushcfunction(L, a_set);
lua_rawset(L, -3);
lua_rawset(L, -3);
lua_pop(L, 1);
a = 99;
if (0 != luaL_dofile(L, "a.lua"))
{
printf("%s\n", lua_tostring(L, -1));
}
printf("a = %f\n\n\n", a);
a = a+1000;
if (0 != luaL_dofile(L, "a.lua"))
{
printf("%s\n", lua_tostring(L, -1));
}
printf("a = %f\n", a);
lua_close(L);
return 0;
}
测试用的 “a.lua”文件
print(a)
a = a+1
print("c=", c)
b = "adas"
print("b=", b)