在Lua中,表達式包括:數值常量、字符串字面值、變量、單目和雙目運算符,函數調用,也包括一些非傳統的函數定義和表結構。
## 1.算術運算符
Lua支持常規的算術運算符:'+', '-', '*', '/', '^', '%', '-'(負)。所有這些運算符都對實數起作用。舉個例子,x^0.5, 計算x的平方根, x^(-1/3),計算x的立方根的反數。
在Lua中,'%'運算符定義規則如下:
a%b == a - floor(a/b)*b
對整型參數來說,它表示常規的意義,結果跟第二個參數b符號相同。
對實數來說,它有一些額外的用途。例如,x%1 表示x的小數部分,x-x%1 表示x的整數部分。類似的,x-x%0.01 將x精確到小數點后2位。

## 2.關系操作符
Lua提供了如下關系操作符:
? ? ? < ? ?> ? ?<= ? ?>= ? ?== ? ?~=
所有這些操作符產生的結果都是true或者false
'=='檢查是否相等,'~='檢查是否不等。這兩個操作符可以作用于任意的兩個值。如果要比較的兩個值是不同的類型,那么Lua認為它們是不等的。否則,Lua根據它們的類型來比較它們是否相等。特例,nil只等于它本身。
Lua根據引用來比較table, userdata, function,也就是說,只有二者是同一個對象的時候,它們才相等。例如:
~~~
a = {}; a.x = 1; a.y = 0
b = {}; b.x = 1; b.y = 0
c = a
~~~
執行下上面的代碼,你可以得到, a == c, 但是 a ~= b

我們把<, >, <=, >=稱為order operator。
order operator只能應用于數值和字符串。Lua根據字母表順序來比較字符串的大小,字母表的順序由本地設置決定。非數值和字符串的值只能比較相等或者不相等,不能用于order operator。
當比較兩個不同類型的值時,一定要小心:記住"0"和0是不同的。除此以外,2<15顯然是true的,但是"2"<"15"是false的(根據字母表順序比較)。為了避免不一致的結果,當你將string和number混合使用到order operator時,例如 2<"15",Lua會產生一個runtime error。

## 3.邏輯運算符
邏輯運算符有:and, or, not。跟控制結構(if,while等)類似,所有的邏輯操作符把false和nil認為是false,其他的任意值都為true。
and:如果第一個參數為false,返回第一個參數,否則返回第二個參數。
or ? :如果第一個參數為false,返回第二個參數,否則返回第一個參數。
~~~
print(4 and 5) ----> 5
print(nil and 13) ----> nil
print(false and 13) ----> false
print(4 or 5) ----> 4
print(false or 5) ----> 5
~~~
'and'和'or'都是用short-cut計算方式,也即是說,只有在有需要的時候,才會去計算第二個參數的值。這樣保證了類似(type(v)=="table" and v.tag=="h1")這樣的表達式不會產生run-time error。(當v不是table類型時,Lua不會去計算v.tag的值)。
有用的Lua表達式:x = x or v,等價于:
if not x then x = v end
(加上x沒有被賦值為false),如果x沒有被設置,那么給它個默認值v。
另一個有用的Lua表達式:a and b or c,等價于C表達式 a ? b : c,(假設b不為false)。例如,我們可以用下面的語句來得到x和y的最大值。
max = (x >y) and x or y
當 x>y,第一個and表達式結果為第二個參數x,x總是true(因為x為一個數值),那么or表達式的結果為x or y,結果為x。
當 x<y,第一個and表達式的結果為false,那么or表達式的值就為false or y,結果為y。
'not'操作符總是返回true或者false
~~~
print(not nil) --> true
print(not false) --> true
print(not 0) --> false
print(not not nil) --> false
~~~
## 4.連接操作符
Lua用'..'(兩個點)來表示string連接符。如果它的任一個操作數為數字,Lua會把它轉為string。
~~~
print("Hello " .. "World") --> Hello World
print(0 .. 1) --> 01
~~~
不要忘了,Lua中的string是常量。string連接操作符會創建一個新的string,不會對它的操作數有任何修改:
~~~
a = "Hello"
print(a .. " World") --> Hello World
print(a) --> Hello
~~~
## 5.優先級
Lua中的操作符優先級,如下表所示,從高到低
~~~
^
not # -(單目)
* / %
+ -
..
< > <= >= ~= ==
and
or
~~~
除了'^和'..',所有的雙目操作符都是左關聯的。因此,下表中,左面的表達式和右面的表達式是等價的:
~~~
a+i < b/2+1 <--> (a+i) < ((b/2)+1)
5+x^2*8 <--> 5+((x^2)*8)
a<y and y<=z <--> (a<y) and (y<=z)
-x^2 <--> -(x^2)
x^y^z <--> x^(y^z)
~~~
在有疑問的時候,就用括號'()',這比查手冊更方便和簡單,而且,當你以后看代碼的時候,你可能仍然有同樣的疑問,顯式地使用括號'()'會更直觀一點。
## 6.表構造函數
構造函數是一個用來初始化表(table)的表達式。它是Lua的一個獨特特性和很強大的功能之一。
最簡單的構造函數是空構造函數,{},創建一個空table。構造函數也可以初始化數組,例如:
~~~
days = {"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"}
~~~
將day[1]初始化為"Sunday", day[2]為"Monday",注意,index是從1開始。
~~~
print(day[4]) --> Wednesday
~~~
Lua提供一個專門的語法去初始化record-like table,如下:
~~~
a = {x=10, y=20}
~~~
等價于
~~~
a = {}, a.x = 10; a.y = 20
~~~
不管我們用什么構造函數去創建一個table,我們都可以增加或減少結果中的field:
~~~
w = {x=0, y=0, label="console"}
x = {math.sin(0), math.sin(1), math.sin(2)}
w[1] = "another filed" -- add key 1 to table 'w'
x.f = w -- add key 'f' to table 'x'
print(w["x"]) --> 0
print(w[1]) --> another field
print(x.f[1]) --> another field
w.x = nil -- remove field 'x'
~~~
也就是說,table創建過程是相同的。構造函數只是將其初始化而已。
Lua每次使用構造函數,都會創建并初始化一個新的table。因此,我們可以用table來實現一個list:
~~~
list = nil
for line in io.lines() do
list = {next=list, value=line}
end
~~~
這些代碼從stdin讀入行,然后存入一個list中,順序跟讀入的順序相反。list中的每個node有兩個field:value,包含行的內容,next,指向下一個node。下面的代碼遍歷這個list,并且打印它的內容:
~~~
local l = list
while l do
print(l.value)
l = l.next
end
~~~
以上兩段代碼的示例:

(由于我們在棧上實現了list,打印的時候會是逆序的)。盡管實現很方便,但是我們在Lua程序中很少使用如上實現的list;List可以作為array得到更好的實現,我們會在后面再講這個問題。
我們可在一個構造函數中同時使用record-style和list_style的初始化方式:
~~~
polyline = {color="blue", thickness=2, npoints=4,?
? ? ? ? ? {x=0, ? y=0},?
? ? ? ? ? {x=-10, y=0},?
? ? ? ? ? {x=-10, y=1},?
? ? ? ? ? {x=0, ? y=1}
? ? ? ? ?}
~~~
上面的例子也說明了如何使用嵌套的構造函數來表示更復雜的數據結構。每一個polyline[i]都是一個table,表示一條記錄(record):
~~~
print(polyline[2].x) --> -10 --此處要注意index 1是從哪里開始的,下面的示例may be helpful
print(polyline[4].y) --> 1
~~~

這兩種形式的構造函數(record-style和list_style)都有一些局限性。一些負數或者string不能作為標識符。

因此,Lua提供了一種更通用的格式。在這個格式中,我們顯式的寫出每一個[index]。
~~~
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]) --> ---
~~~
這個規則有點麻煩,但是更方便靈活:record-style和list_style是這個通用格式的兩個特例而已。
~~~
{x=0, y=0} <==> {["x"]=0, ["y"]=0}
{"r", "g", "b"} <==> {[1]="r", [2]="g", [3]="b"}
~~~
有時候,你想要你的array的index從0開始(Lua默認從1開始),用下面的方式就可以了:
~~~
days = {[0]="Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}
~~~
現在,第一個值"Sunday", index為0 。它不會影響其他的field;"Monday"的index為1,因為它是構造函數中的第一個list值;其他的跟隨。盡管實現很便利,但是不推薦這樣用。Lua的很多內置函數都假設array的index從1開始,如果一個array從0開始,可能會在處理上有問題。
在最后一個元素后面,可以加逗號','。這個末尾的逗號','是可選的,但都是合法的:
~~~
a = {[1]="red", [2]="green", [3]="blue",}
~~~
通過這個便利性,程序在生成Lua table的時候不需要對最后一個元素做特殊處理。
最后,我們可以使用分號';'來代替逗號',',你可以在用';'來分割table中的不同屬性的部分,例如:
~~~
{x=10, y=45; "one", "two", "three"}
~~~
水平有限,如果有朋友發現錯誤,歡迎留言交流。