Lua 任意类型的get/set方法

来源:互联网 发布:淘宝怎么回收手机 编辑:程序博客网 时间:2024/05/17 19:56

Lua任意类型的get/set方法

对于luaC程序相互调用时,如果有一个数字需要在C程序和lua脚本同时使用,这时就需要保持lua程序与C程序中的数字变量一致,及当C程序改变了这个数字变量时lua能够获取改变后的值,当lua程序改变了变量时C程序也可以获取改变后的值。实现这个功能可以给lua变量设置get/set方法。当lua中读取数字变量的值时,则调用对应得get方法,get方法中可以调用C程序中的一个get获取到C程序中数字变量的值,同理给数字变量赋值时也一样。这样lua中使用的数字变量的值就是C程序中的变量值,从而保持一直。

 

使用lua实现get/set方法

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] = vhandlers[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 变量endattr_setup()print(c) -->nilprint(type(c), "\n\n") -->nila = 15print(a) -->15print(type(a), "\n\n")--numberb = { x = 10};print(b.x) -->10print(type(b), "\n\n")-->tableprint("rawget(_G, \'b\')", rawget(_G, 'b')) -->nil

C代码实现


C代码
#include<iostream>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 */#elselua_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+1print("c=", c)b = "adas"print("b=", b)

运行结果:





原创粉丝点击