第 3 章 · 表:宿主与脚本的交界 章节摘要:表是 Lua 唯一的复合数据结构,也是宿主与脚本之间唯一的复合数据公约。本章两节:3.1 讲表的创建语法与"数组加哈希"的双重身份,看一张结构如何同时胜任数组、记录、命名空间与对象;3.2 讲遍历(ipairs 与 pairs 的分工)、长度操作符的边界陷阱,以及表在配置、缓存、与宿主交换数据处的典型用法。读完你会同意:学会表,等于学会了半个 Lua。 学习目标 阅读完本章,你应当能够: 熟练使用表构造器的三种写法(空表、数组式、记录式混排),解释 、 与位置初始化各自适合的场合; 说清表"数组部分与哈希部分"的内部分工,理解为什么整数键连续时遍历与长度更快; 区分 ipairs 与 pairs 的语义与适用边界,手写一个无状态迭代器;
章节摘要:表是 Lua 唯一的复合数据结构,也是宿主与脚本之间唯一的复合数据公约。本章两节:3.1 讲表的创建语法与"数组加哈希"的双重身份,看一张结构如何同时胜任数组、记录、命名空间与对象;3.2 讲遍历(ipairs 与 pairs 的分工)、长度操作符的边界陷阱,以及表在配置、缓存、与宿主交换数据处的典型用法。读完你会同意:学会表,等于学会了半个 Lua。
阅读完本章,你应当能够:
[k]=v、k=v 与位置初始化各自适合的场合;结构越少,约定越牢:宿主只需认识一张表,就能与整个脚本世界对话。
从构造器的三种写法进表的世界,然后直入内部视角:一张表同时维护数组段与哈希段,两段的分工决定了性能与语义。键的合法性(nil 与 NaN 不能当键)、引用作键的用法、表作为命名空间的组织术,都在这一节。
ipairs 只走 1 到 n、pairs 全表乱序;#t 在有洞时实现相关——这两条"缺陷"其实是同一件事的两面:边界即数组段长度。讲清边界概念后,用四个应用场景收束全章:配置中心、缓存与去重、脚本侧对象字典、与宿主交换数据的桥。每个场景都有可运行代码。
一句话论点:3.1 讲"表是什么"(结构与创建),3.2 讲"表怎么用"(遍历与场景),中间的桥梁是"边界"概念——数组段的连续性。
3.1 双重身份:构造器 · 数组段与哈希段 · 键的规矩 │ ▼ 边界 border:连续整数键的长度 3.2 遍历与长度:ipairs 停在边界 · pairs 全表 · 洞的陷阱 │ ▼ 四个场景:配置 · 缓存 · 字典 · 宿主之桥 (对象与继承场景留给第 5 章,用元表升级表的能力)
为什么一门语言敢只有一种复合结构? 因为数组、字典、对象、命名空间在"键到值"这个抽象下同构——数组是整数键的特例,对象是字符串键加函数值,命名空间是模块级的组织约定。宿主与脚本之间只需要为这一种结构定协议(C 侧三个原语就能交换任意嵌套数据),边界的维护成本压到最低。
引用语义意味着哪三件事? 赋值传引用(两个名字一张表)、比较按引用(内容相等要深比较)、生命周期归 GC(还有引用就还活着)。3.1 节的深拷贝、3.2 节的缓存清理都是这三条的推论。
nil 在表里扮演什么角色? "键不存在"的标准答案:读不存在的键得 nil、给键赋 nil 即删除。它同时是边界问题的根源(数组中段的 nil 制造"洞")与配置语义的基石("没填"与"显式否定"要分开)。
如果本章只允许记三句话,记这三句:
**第一句:一个结构,三种身份,无数形态。**数组、字典、命名空间不是三种东西,是同一种东西的三种用法——判断"该用什么结构"时先想到表,再用"顺序、键、边界"三问决定用法。
第二句:边界即纪律。#、ipairs、table.concat 只在"无洞的连续段"上行为确定。造洞是表世界的唯一原罪——删中间元素用 remove,稀疏需求换字典,长度拿不准自己记账。
**第三句:表是会客厅。**宿主注入的 API 是表、交换的数据是表、返回的结果是表——两边的一切往来都发生在这张桌子上。读懂一张表的结构约定,就读懂了那个宿主的接口设计。