Lua Table 简介
- Table 结构:在Lua中,table是一种可以存储键值对的数据结构,它既可以用作数组(通过数字索引来访问元素),也可以用作字典(通过任意类型作为键),作为二者的结合体使用也是可以的
- 索引:除了 nil 和 NaN 外,任何Lua值都可以作为table的索引。
- 动态调整大小:table没有固定的大小限制,你可以根据需要添加或删除元素。
- 内存管理:由于Lua的垃圾收集机制,当没有任何引用指向table时,它将被自动回收。 相应的代码Lua层面构造表的使用
CPP的基本调用Lua脚本代码
代码语言:cpp复制#include <stdio.h>
#include <lua.hpp>
int mian()
{
lua_State* L = luaL_newstate();
luaL_openlibs(L);
luaL_dofile(L, "LuaTableTest.lua");
lua_close(L);
return 0;
}
表是Lua特有的功能强大的东西。
在Lua脚本中,可以使用 {} 来创建一个空表,并通过直接赋值的方式来初始化数组或字典。例如,通过 myTablekey = value 的形式,可以向表中添加元素。
1.Lua构造表使用例
代码语言:lua复制-- LuaTableTest.lua
-- 创建一个空表
local myTable = {}
-- 作为数组使用
myTable[1] = "Hello"
myTable[2] = "World"
-- 作为字典使用
myTable.name = "Alice"
myTable.age = 25
-- 遍历table
for k, v in pairs(myTable) do
print(k, v)
end
-- 输出: 输出顺序是随机的,因为TableTable的遍历顺序是随机的
-- 1 Hello
-- 2 World
-- name Alice
-- age 25
2.Lua表库函数使用例
Lua提供了一组丰富的内置函数来帮助操作table,比如table.concat用于连接表中的元素为一个字符串,table.insert用于在指定位置插入新的元素,table.move用于移动表中的元素,table.remove用于移除元素等。
另外,无论何时,若一个操作需要取表的长度,这张表必须是一个真序列,或是拥有 __len 元方法。所有的库函数都忽略传入参数的那张表中的非数字键。
1.链接.插入.移动.移除演示
- table.concat (list , sep , i , j)
- list:表
- sep:分隔符,默认值是空串
- i:起始索引,默认为1
- j:结束索引,默认为#list
提供一个列表,其所有元素都是字符串或数字,
返回指定表中从start位置到end位置且每个元素以特定分隔符分割的字符串
注意:当使用 table.concat 函数时,它默认会按照数值索引的顺序连接表中的元素,忽略非数值索引的键值对。
- table.insert (list, pos, value)
- list: 表
- pos: 位置(Lua的索引是从1开始的)
- value: 值
在 list 的位置 pos 处插入元素 value , 并后移元素 listpos, listpos 1, ···, list#list 。 pos 的默认值为#list 1既数组末尾 , 因此调用 table.insert(t,x) 会将 x 插在列表 t 的末尾。
- table.move (a1, f, e, t ,a2)
- a1: 源表
- f: 开始索引
- e: 结束索引
- t: 目标索引
- a2: 目标表,默认为a1
将开始索引到结束索引区间内的元素从表 a1 移动到表 a2目标索引开始的位置。
目标区间可以和源区间重叠。 索引 f 必须是正数。
- table.remove (list , pos)
- list: 表
- pos: 位置,默认为#list
移除 list 中 pos 位置上的元素,并返回这个被移除的值。 当 pos 是在 1 到 #list 之间的整数时, 它向前移动元素 listpos 1, listpos 2, ···, list#list 并删除元素 list#list; 索引 pos 可以是 #list 1 ,或在 #list 为 0 时可以是 0 ; 在这些情况下,函数删除元素 listpos。
代码语言:lua复制-- LuaTableFunc.lua
local src = {a=1, b=2,'a', 'b', 'c', 'd'}
-- 数值索引:1='a', 2='b', 3='c'
-- 字符串键:'a'=1, 'b'=2 a=1和b=2是非数字键索引被忽略了
-- concat
print('-------------concat------------')
print(table.concat(src, ',')) -- 输出: a,b,c,d --忽略了a=1,b=2的值
print(table.concat(src, '|',1,3)) -- 输出: a|b|c
table.insert(src, 2, 'x') -- 在2的位置插入x
print(table.concat(src, '#')) -- 输出:a#x#b#c#d
-- insert
print('-------------insert------------')
local insertTest = {1, 2, 3}
table.insert(insertTest, 1, 'a') -- 在1的位置插入a
print(table.concat(insertTest, ',')) -- 输出: a,1,2,3
-- move
print('-------------move------------')
local moveTest = {}
table.move(src, 1, 3, 1, moveTest)
print(table.concat(moveTest, '|')) -- 输出: a|x|b
-- remove
print('----------------remove-----------')
local removeTest = {1, 2, 3}
print('remove:'..table.remove(removeTest)) -- remove:3
print(table.concat(removeTest, ',')) -- 输出 1,2
table.insert(removeTest,'3') -- 在末尾插入3
print(table.concat(removeTest, '|')) -- 输出 1|2|3
2.sort和pack跟unpack函数示例
- table.sort (list , comp)
- list: 表
- comp: 比较函数,默认使用 <
可以类比于cpp里的sort库函数
注意:当内容中既有number类型又有string类型的元素时,无法进行排序。
在表内从 list1 到 list#list 原地 对其间元素按指定次序排序。 如果提供了 comp , 它必须是一个可以接收两个列表内元素为参数的函数。 当第一个元素需要排在第二个元素之前时,返回真 (因此 not comp(listi 1,listi) 在排序结束后将为真)。 如果没有提供 comp, 将使用标准 Lua 操作 < 作为替代品。
- table.pack (···) 返回用所有参数以键 1,2, 等填充的新表, 并将 "n" 这个域设为参数的总数。 注意这张返回的表不一定是一个序列。
- table.unpack (list , i , j)
- list: 表
- i: 起始索引,默认为1
- j: 结束索引,默认为#list
返回列表中的元素。 这个函数等价于return listi, listi 1, ···, listj
i 默认为 1 ,j 默认为 #list。
代码语言:lua复制-- LuaTableFunc.lua
-- sort
print('-------------sort------------')
local sortTest = {'b', 'a', 'c', 'd'}
table.sort(sortTest)
for i,v in ipairs(sortTest) do
print(i,v)
end
-- 输出
-- 1 a
-- 2 b
-- 3 c
-- 4 d
-- pack And unpack
print('-------------pack--unpack---------')
local packTest = table.pack(4, 3, 2, 1)
print(packTest.n) -- 输出: 4 -- n是数组的长度
print(table.unpack(packTest)) -- 输出: 4 3 2 1
print(table.unpack(packTest, 2, 3)) -- 输出: 3 2
C/C 层面构造表的使用
在C/C 中,通过Lua API可以创建和操作Lua表。例如,可以使用lua_newtable来创建一个新的空表,并使用lua_pushstring和lua_setfield来设置表中的键值对。此外,还可以通过lua_setglobal将表设置为全局变量,以便在Lua脚本中访问。之后,通过加载并执行Lua脚本来处理这些表。
1.CPP层面代码
代码语言:cpp复制// lua_pop(L,弹出栈顶元素数量1开始 );
#include <stdio.h>
#include <lua.hpp>
int main()
{
// 创建一个虚拟机
lua_State* L = luaL_newstate();
// 加载一些常用的系统库
luaL_openlibs(L);
/*------创造一个表,并设置键值对------ */
lua_newtable(L); // 创建一个新的 Lua 表,并将其压入栈顶。
lua_pushstring(L, "xmr"); // 将字符串 "xmr" 压入栈顶。
lua_setfield(L, 1, "name"); // 将栈顶的值设置为表中键 "name" 对应的值。
// 此时栈顶的值是 "xmr",而索引 1/-2 指向的是刚创建的表,因此相当于为表添加了一个键 "name" 和对应的值 "xmr"。
lua_pushstring(L, "Hello World"); // 将字符串 "Hello World" 压入栈顶。
lua_rawseti(L, -2, 1); // 将栈顶的值设置为表中索引 1 对应的值。
// 这里使用 `-2`/用1也可以,一般建议用-2 是为了获取表的索引(即上一步创建的表),然后设置索引 1 的值为 "Hello World"。
lua_setglobal(L, "tab"); // 将当前创建的表设置为全局变量 "tab"。
// 此时栈顶的值是刚创建的表,该表有两个元素:`name = "xmr"` 和 `[1] = "Hello World"`。
/*--------------------------------*/
// 加载 Lua 文件并执行,文件名为 "luaTableTest.lua"
if (luaL_dofile(L, "CTestLuaTable.lua"))
{
// 如果 Lua 文件执行失败,则 Lua 错误会被压入栈顶。
printf("%sn", lua_tostring(L, -1)); // 输出错误信息。
}
// 关闭虚拟机
lua_close(L);
return 0;
}
//代码流程总结
//创建 Lua 虚拟机:使用 luaL_newstate() 创建一个新的 Lua 虚拟机实例。
//加载 Lua 标准库:使用 luaL_openlibs() 加载 Lua 标准库。
//创建 Lua 表:
//使用 lua_newtable() 创建一个新的空表,并将其压入栈顶。
//使用 lua_pushstring() 和 lua_setfield() 设置表中键 "name" 的值为 "xmr"。
//使用 lua_pushstring() 和 lua_rawseti() 设置表中索引 1 的值为 "Hello World"。
//设置全局变量:使用 lua_setglobal() 将创建的表设置为全局变量 "tab"。
//执行 Lua 脚本:使用 luaL_dofile() 加载并执行 Lua 脚本 "luaTableTest.lua"。
//输出结果:脚本执行后,输出表 "tab" 中键 "name" 和索引 1 对应的值。
//关闭虚拟机:使用 lua_close() 关闭 Lua 虚拟机。
2.Lua接收到CPP传过来的表使用例
在Lua脚本中,可以简单地通过全局变量名来访问由C/C 创建并设置的表,例如print(tab.name)和print(tab1),分别输出表tab中键name和索引1对应的值。
代码语言:lua复制-- CTestLuaTable.lua
print(tab.name) -- 输出表 "tab" 中键 "name" 对应的值。
print(tab[1]) -- 输出表 "tab" 中索引 1 对应的值。
总结
在Lua中,table是一种非常灵活且强大的数据结构,它可以用来存储键值对,既可以作为数组使用(通过数字索引来访问元素),也可以作为字典使用(通过任意类型作为键)。这种灵活性使得table成为了Lua中处理数据的主要工具之一。table没有固定的大小限制,可以根据需要动态地添加或删除元素,并且由于Lua的自动垃圾回收机制,当没有任何引用指向一个table时,它将被自动回收,从而有效地管理内存。