array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 用户自定义类型 - 爱码网

userdata:

userdata机制可以让我们在lua中使用c中的自定义数据类型。userdata表示一块动态分配的内存,这块内存就存储的自定义类型的数据,在lua脚本中使用userdata,并配合c提供的函数,就可以操作userdata了。

 

定义一个player类型:

typedef struct _Player {
    int id; 
    char name[20];
    int account;
} Player;

定义player的所有操作:

static int _index = 1;
static int player_new (lua_State* L) {
    const char* name = luaL_checkstring(L, 1);
    int len = strlen(name);

    Player* player = (Player*)lua_newuserdata(L, sizeof(Player)); // 使用lua_newuserdata创建userdata,并将其入栈
    player->id = _index++;
    memcpy(player->name, name, len + 1); // 需要拷贝一份字符串,否则栈在弹出的时候,字符串会被销毁
    player->account = 0;
    
    return 1;
}
static int player_print (lua_State* L) {
    Player* player = (Player*)lua_touserdata(L, 1);
    
    printf("player data: %d %s acount:%d \n", player->id, player->name, player->account);
    
    return 0;
}
static int player_charge (lua_State* L) {
    Player* player = (Player*)lua_touserdata(L, 1);
    int add = luaL_checkint(L, 2);
    
    player->account += add;
    
    return 0;
}

lua代码:

local player = Player.new("xiaoming")
local player1 = Player.new("xiaoqiang")

Player.charge(player1, 20)
Player.charge(player, 101)
Player.print(player)
Player.print(player1)

 

元表:

1. 相同的元表代表相同的类型,因此,我们也使用元表来为userdata标示类型:

为userdata设置元表:

const char* CLASS_NAME_PLAYER = "Player_Class";

Player* player = lua_newuserdata(L, sizeof(Player));

lua_newmetatable(L, CLASS_NAME_PLAYER); // 创建一个新的元表,名字为player_class,并入栈

lua_setmetatable(L, -2); // 为位置在-2的userdata,设置元表,元表出栈

如何使用元表来进行类型判断:

Player* player = (Player*)lua_touserdata(L, 1);

改为

Player* player = (Player*)lua_checkudata(L, 1, CLASS_NAME_PLAYER); 如果userdata的类型不匹配,将抛出错误

2. 在lua中,元表除了可以标示类型,更重要的是模拟面向对象,和普通lua对象一样,userdata同样可以使用元表机制来模拟面向对象:

我们首先创建一个元表,只需要把对象的方法放在元表上,最重要的是设置元表的__index元方法:

luaL_newmetatable(L, CLASS_NAME_PLAYER); // 创建一个新的元表,并入栈,该元表是存放在全局作用域中的

...... // 设置一些对象方法

lua_pushvalue(L, -1); // 复制元表

lua_setfield(L, -2, "__index"); // 将元表的__index元方法设置为自己

在创建新对象的时候,只需要将新对象的元表设置为已经创建好的元表:

luaL_getmetatable(L, CLASS_NAME_PLAYER); // 将元表入栈

lua_setmetatable(L, -2); // 设置元表,元表出栈

上面的例子改为:

c代码:

static int _index = 1;
const char* CLASS_NAME_PLAYER = "PLAYER_CLASS";
static int player_new (lua_State* L) {
    dump(L);
    
    const char* name = luaL_checkstring(L, 1);
    int len = strlen(name);
    
    dump(L);
    
    Player* player = (Player*)lua_newuserdata(L, sizeof(Player));
    dump(L);
    player->id = _index++;
    memcpy(player->name, name, len + 1);
    player->account = 0;
    
  // 使用已经创建好的元表 luaL_getmetatable(L, CLASS_NAME_PLAYER); lua_setmetatable(L,
-2); return 1; } static int player_print (lua_State* L) { Player* player = (Player*)luaL_checkudata(L, 1, CLASS_NAME_PLAYER); printf("player data: %d %s acount:%d \n", player->id, player->name, player->account); return 0; } static int player_charge (lua_State* L) { Player* player = (Player*)luaL_checkudata(L, 1, CLASS_NAME_PLAYER); int add = luaL_checkint(L, 2); player->account += add; return 0; } int libopen_player (lua_State* L) {
  // 创建元表 luaL_newmetatable(L, CLASS_NAME_PLAYER); lua_pushcfunction(L, player_print); lua_setfield(L,
-2, "print"); lua_pushcfunction(L, player_charge); lua_setfield(L, -2, "charge"); lua_pushvalue(L, -1); lua_setfield(L, -2, "__index"); lua_settop(L, 0);
  // 模块只有一个new方法了 lua_newtable(L); lua_pushcfunction(L, player_new); lua_setfield(L,
-2, "new"); lua_setglobal(L, "Player"); return 1; }

lua代码:

local player = Player.new("xiaoming")
local player1 = Player.new("xiaoqiang")

player1:charge(30)
player:charge(20)
player:print()
player1:print();

 

轻量级的userdata:

对比完全的userdta,轻量级的userdata只是c对象的一个指针,没有元表,就是一个普通的lua对象,就像number一样,因此轻量级的userdata不受lua垃圾回收机制的控制,必须自己管理内存。

c代码:

Player* player = nullptr;
static int player_pointer (lua_State* L) {
    player = new Player();
    player->id = 12;
    memcpy(player->name, "wulin", 6);
    player->account = 0;
    
    lua_pushlightuserdata(L, player);
    
    return 1;
}

lua代码:

local player1 = Player.pointer();
local player2 = Player.pointer();

print(player1);
print(player2);

 

userdata的内存回收:

userdata属于lua的内存管理机制,因此无须关系userdata的内存问题,但如果userdata使用了一些c内存中的对象,并且需要在userdata被删除的时候,同时删除这些对象,那么lua的内存回收机制就无能力为。这种情况下,lua为我们提供了一个__gc元方法(只针对userdata),当userdata被删除时,会调用这个元方法,并将userdata作为参数传入,这样我们就可以删除userdata中引用的c对象了。

在player中添加一个__gc的元方法:

static int player_delete (lua_State* L) {
    Player* player = (Player*)luaL_checkudata(L, 1, CLASS_NAME_PLAYER);
    
    printf("delete something not in lua memory... player name:%s \n", player->name);
    
    return 0;
}
int libopen_player (lua_State* L) {
    luaL_newmetatable(L, CLASS_NAME_PLAYER);
    lua_pushcfunction(L, player_print);
    lua_setfield(L, -2, "print");
    lua_pushcfunction(L, player_charge);
    lua_setfield(L, -2, "charge");
    lua_pushvalue(L, -1);
    lua_setfield(L, -2, "__index");
    lua_pushcfunction(L, player_delete);
    lua_setfield(L, -2, "__gc"); // 添加__gc元方法
    lua_settop(L, 0);
    
    lua_newtable(L);
    lua_pushcfunction(L, player_new);
    lua_setfield(L, -2, "new");
    lua_pushcfunction(L, player_pointer);
    lua_setfield(L, -2, "pointer");
    lua_setglobal(L, "Player");
    
    return 1;
}

lua代码:

local player = Player.new("xiaoming")
player:charge(20)
player:print()

player = nil

collectgarbage(); // 强制进行垃圾回收

 

相关文章:

  • 2019-01-22
  • 2018-04-27
  • 2021-12-28
  • 2019-09-08
  • 2019-12-03
  • 2021-04-18
  • 2021-06-13
  • 2020-04-26
猜你喜欢
  • 2018-04-26
  • 2019-09-15
  • 2021-08-26
  • 2021-08-16
  • 2018-06-13
  • 2018-03-07
  • 2018-09-09
  • 2020-11-14
相关资源
相似解决方案