Lua学习笔记:Lua里table表的使用例及介绍

2024-09-08 11:01:37 浏览数 (2)

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时,它将被自动回收,从而有效地管理内存。

0 人点赞