Lua 任意类型的get/set方法

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] = 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

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 */
#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)

运行结果:





  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值