第一版是为 Lua 5.0 编写的。虽然在很大程度上仍然适用于更高版本,但有一些差异。
第四版针对 Lua 5.3,可以在 亚马逊 和其他书店买到。
购买此书,您还将帮助 支持 Lua 项目


3.6 – 表格构造函数

构造函数是创建和初始化表格的表达式。它们是 Lua 的一个独特特性,也是其最有用和最通用的机制之一。

最简单的构造函数是空构造函数 {},它创建一个空表格;我们之前已经看到过它。构造函数还可以初始化数组(也称为序列列表)。例如,语句

    days = {"Sunday", "Monday", "Tuesday", "Wednesday",
            "Thursday", "Friday", "Saturday"}
将使用字符串 "Sunday" 初始化 days[1](第一个元素的索引始终为 1,而不是 0),使用 "Monday" 初始化 days[2],依此类推
    print(days[4])  --> Wednesday

构造函数不必只使用常量表达式。我们可以对每个元素的值使用任何类型的表达式。例如,我们可以构建一个简短的正弦表,如下所示

    tab = {sin(1), sin(2), sin(3), sin(4),
           sin(5), sin(6), sin(7), sin(8)}

为了初始化一个用作记录的表格,Lua 提供了以下语法

    a = {x=0, y=0}
它等效于
    a = {}; a.x=0; a.y=0

无论我们使用什么构造函数来创建表格,我们始终可以向其中添加和删除任何类型的其他字段

    w = {x=0, y=0, label="console"}
    x = {sin(0), sin(1), sin(2)}
    w[1] = "another field"
    x.f = w
    print(w["x"])   --> 0
    print(w[1])     --> another field
    print(x.f[1])   --> another field
    w.x = nil       -- remove field "x"
也就是说,所有表格都是平等创建的;构造函数只会影响它们的初始化。

Lua 每当计算一个构造函数时,就会创建一个新的表格并对其进行初始化。因此,我们可以使用表格来实现链表

    list = nil
    for line in io.lines() do
      list = {next=list, value=line}
    end
此代码从标准输入中读取行,并按相反的顺序将它们存储在链表中。列表中的每个节点都是一个包含两个字段的表格:value,其中包含行内容,以及 next,其中包含对下一个节点的引用。以下代码打印列表内容
    l = list
    while l do
      print(l.value)
      l = l.next
    end
(因为我们把列表实现为栈,所以行将按相反的顺序打印。)尽管具有指导意义,但我们在实际的 Lua 程序中几乎不使用上述实现;列表最好实现为数组,正如我们在 第 11 章 中看到的那样。

我们可以在同一个构造函数中混合使用记录样式和列表样式的初始化

    polyline = {color="blue", thickness=2, npoints=4,
                 {x=0,   y=0},
                 {x=-10, y=0},
                 {x=-10, y=1},
                 {x=0,   y=1}
               }
上述示例还说明了我们如何嵌套构造函数来表示更复杂的数据结构。每个元素 polyline[1]、...、polyline[4] 都是表示记录的表
    print(polyline[2].x)    --> -10

这两种构造函数形式都有其局限性。例如,您不能使用负索引或不是正确标识符的字符串索引来初始化字段。对于此类需求,还有另一种更通用的格式。在此格式中,我们显式地将要初始化的索引写为方括号中的表达式

    opnames = {["+"] = "add", ["-"] = "sub",
               ["*"] = "mul", ["/"] = "div"}
    
    i = 20; s = "-"
    a = {[i+0] = s, [i+1] = s..s, [i+2] = s..s..s}
    
    print(opnames[s])    --> sub
    print(a[22])         --> ---
这种语法比较繁琐,但更灵活:列表样式和记录样式形式都是这种更通用形式的特例。构造函数
    {x=0, y=0}
等效于
    {["x"]=0, ["y"]=0}
和构造函数
    {"red", "green", "blue"}
等效于
    {[1]="red", [2]="green", [3]="blue"}

对于那些真的希望他们的数组从 0 开始的人来说,编写以下内容并不难

    days = {[0]="Sunday", "Monday", "Tuesday", "Wednesday",
            "Thursday", "Friday", "Saturday"}
现在,第一个值 "Sunday" 位于索引 0 处。该零不影响其他字段,但 "Monday" 自然转到索引 1,因为它是构造函数中的第一个列表值;其他值紧随其后。尽管有此便利,我不建议在 Lua 中使用从 0 开始的数组。请记住,大多数函数都假定数组从索引 1 开始,因此不会正确处理此类数组。

您始终可以在最后一个条目后加一个逗号。这些尾随逗号是可选的,但始终有效

    a = {[1]="red", [2]="green", [3]="blue",}
这种灵活性使得编写生成 Lua 表的程序变得更加容易,因为它们不需要将最后一个元素作为特殊情况处理。

最后,您始终可以在构造函数中使用分号而不是逗号。我们通常保留分号来分隔构造函数中的不同部分,例如将其列表部分与其记录部分分隔开

    {x=10, y=45; "one", "two", "three"}