days = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
will initialize days[1]
with the string "Sunday"
(the first element has always index 1, not 0), days[2]
with "Monday"
, and so on:
print(days[4]) --> Wednesday table從1開始,不是從0開始
還有一點,訪問不存在的index不會報錯,只是返回nil。
Constructors do not need to use only constant expressions. We can use any kind of expression for the value of each element. For instance, we can build a short sine table as
tab = {sin(1), sin(2), sin(3), sin(4), sin(5), sin(6), sin(7), sin(8)}
To initialize a table to be used as a record, Lua offers the following syntax: table作為record使用
a = {x=0, y=0}
which is equivalent to
a = {}; a.x=0; a.y=0
No matter what constructor we use to create a table, we can always add and remove other fields of any type to it:
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"
That is, all tables are created equal; constructors only affect their initialization.
Every time Lua evaluates a constructor, it creates and initializes a new table. Consequently, we can use tables to implement linked lists:
每次執行一個構造函數,lua創建和初始化一個新的table,因此,你可以使用table來實現linked list.
list = nil
for line in io.lines() do
list = {next=list, value=line}
end
This code reads lines from the standard input and stores them in a linked list, in reverse order. Each node in the list is a table with two fields:value
, with the line contents, andnext
, with a reference to the next node. The following code prints the list contents:
l = list while l do print(l.value) l = l.next end
(Because we implemented our list as a stack, the lines will be printed in reverse order.) Although instructive, we hardly use the above implementation in real Lua programs; lists are better implemented as arrays, as we will see in Chapter 11.
We can mix record-style and list-style initializations in the same constructor:
我們可以混合記錄性風格和列表形風格來初始化。
polyline = {color="blue", thickness=2, npoints=4, {x=0, y=0}, {x=-10, y=0}, {x=-10, y=1}, {x=0, y=1} }
The above example also illustrates how we can nest constructors to represent more complex data structures. Each of the elementspolyline[1]
, ...,polyline[4]
is a table representing a record:
這里例子也展示了可以嵌套構造函數來表示復雜的結構。
print(polyline[2].x) --> -10
Those two constructor forms have their limitations. For instance, you cannot initialize fields with negative indices, or with string indices that are not proper identifiers. For such needs, there is another, more general, format. In this format, we explicitly write the index to be initialized as an expression, between square brackets: 用[exp]表示索引
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]) --> ---
That syntax is more cumbersome, but more flexible too: Both the list-style and the record-style forms are special cases of this more general one. The constructor 這個語法更笨重,但是比較靈活。list-style和record-style是這種一般化形式的特例。
{x=0, y=0}
is equivalent to
{["x"]=0, ["y"]=0}
and the constructor
{"red", "green", "blue"}
is equivalent to
{[1]="red", [2]="green", [3]="blue"}
For those that really want their arrays starting at 0, it is not difficult to write the following:
想要index從0開始,把第一個設置為0,這並不影響其他的,第二個默認為1,因為它是構造函數中的第一個list類型,其他的值跟隨他。
days = {[0]="Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
Now, the first value,"Sunday"
, is at index 0. That zero does not affect the other fields, but"Monday"
naturally goes to index 1, because it is the first list value in the constructor; the other values follow it. Despite this facility, I do not recommend the use of arrays starting at 0 in Lua. Remember that most functions assume that arrays start at index 1, and therefore will not handle such arrays correctly.
不推薦在Lua最開始位置為0,因為大多數函數式是從1開始的。
You can always put a comma after the last entry. These trailing commas are optional, but are always valid:
a = {[1]="red", [2]="green", [3]="blue",} 同php一樣,table后面放分號不影響正確性。
Such flexibility makes it easier to write programs that generate Lua tables, because they do not need to handle the last element as a special case。
Finally, you can always use a semicolon instead of a comma in a constructor. We usually reserve semicolons to delimit different sections in a constructor, for instance to separate its list part from its record part:
{x=10, y=45; "one", "two", "three"}
最后,你可以使用分號代替逗號,我們通常保留分號來區分不同的段。
刪除table
賦值為nil即可。
lua table作為array:
Tables as arrays
First, remember that tables are still just key/value containers, Lua doesn't actually have an array type. But tables can be treated like arrays, which is explained here:
Table constructors can contain a comma separated list of objects to create an "array":
-
> t = {"a", "b", "c"} > = t[1] a > = t[3] c
This is a syntax shortcut for:
-
> t = {[1]="a", [2]="b", [3]="c"} > = t[1] a > = t[3] c
So it's still just a key/value association.
You can also mix the array syntax with the usual key=value syntax:
-
> t = {"a", "b", [123]="foo", "c", name="bar", "d", "e"} > for k,v in pairs(t) do print(k,v) end 1 a 2 b 3 c 4 d 5 e 123 foo name bar
求array length,
-
> t = {"a", "b", "c"} > = #t 3
The #
operator doesn't count all the items in the table (!), instead it finds the last integer (not-fractional number) key. Because of how it's implemented, its results are undefined if all the integer keys in the table aren't consecutive (that is, don't use it for tables used as sparse arrays[2]).
> a={}
> a[1000]=1
> print(#a)
輸出0.
請記住對於所有未初始化的元素的索引結果都是nil。Lua將nil作為定界數組結尾的標志。當一個數組有
“空隙hole”是,即中間含有nil時,長度操作符會認為這些nil元素就是結尾標志,因此應該避免對於那些
含有“空隙”的數組使用#。大多數數組不會包含“空隙”,因此,#一般是安全的。
如果真的需要處理那些含有“空隙”的數組,使用使用table.maxn.他將返回一個table的最大正index。
print(table.maxn(a)) ->1000
There are two ways to add an item to the end of an array:
-
> t = {} > table.insert(t, 123) > t[#t+1] = 456 > = t[1] 123 > = t[2] 456
table.insert
takes an optional index parameter to insert into the middle of an array. It shifts up any other integer keys above the index:
-
> t = {"a", "c"} > table.insert(t, 2, "b") > = t[1], t[2], t[3] a b c
table.remove
removes an item from an array, shifting down any remaining integer keys:
-
> t = {"a", "b", "c"} > table.remove(t, 2) > = t[1], t[2] a c
To loop over an array, use ipairs
. Unlike pairs, it only gives you the consecutive integer keys from 1, and it guarantees their order. With pairs
, the number keys will not necessarily be given in the correct order!
-
> t = {"a", "b", "c"} > for i, v in ipairs(t) do print(i, v) end 1 a 2 b 3 c
To join together an array of strings, there's table.concat
. It takes optional separator, start, and end parameters. Here we only use the separator:
-
> t = {"a", "b", "c"} > = table.concat(t, ";") a;b;c
For a list of all the table.* functions and their complete documentation, see [[3]].
Table values are references
Unlike basic types such as numbers, when you store a table in a new variable, pass it to a function, etc., you don't create a new copy of the table. Instead you get a new reference (think of it like a handle, or pointer) to the same table: table值是引用.
-
> t = {} > u = t > u.foo = "bar" > = t.foo bar > function f(x) x[1] = 2 end > f(t) > = u[1] 2
Tables are freed from memory by the garbage collector sometime after the last reference to them is gone (not necessarily instantly). The garbage collector is designed to work correctly even in the case where a table (directly or indirectly) contains a reference to itself.
A related thing to remember is that table comparison works by reference. Comparing tables using ==
will return false
even if the two tables have the same contents, they must actually be references to the same table.
Finally, if you want to copy a table, you'll have to do it manually. Lua offers no standard function for it, mainly because of all the different ways you can copy a table.
Tables as unordered sets
Often people new to Lua will create an array to store a group of objects, even if the order isn't necessary. The problem with this is that removal is slow (need to shift down other items), and checking if an item is in the array is slow (need to loop over all the items).
This can be solved by storing items in the keys and setting values to a dummy value (like true
), so you can use a table like an unordered set with fast insertion, removal, and lookup.
The main differences are that there's no easy way to get the count (you have to use a loop), and you can't store the same item twice in the set.
So if you need to store a group of items, it's best to consider both sets and arrays to see what fits your situation best.
-
local items = {} -- add some items to the set items["foo"] = true items[123] = true -- is "foo" in the set? if items["foo"] then -- do stuff end -- remove item from the set items[123] = nil
-
參考:http://www.lua.org/pil/3.6.html
http://lua-users.org/wiki/TablesTutorial