html
注:本記錄都摘錄自:http://manual.luaer.cn/ , lua在線手冊 。1-2.5部分。程序員
相似 C 的轉義符: '\a
' (響鈴), '\b
' (退格), '\f
' (表單), '\n
' (換行), '\r
' (回車), '\t
' (橫向製表), '\v
' (縱向製表), '\\
' (反斜槓), '\"
' (雙引號), 以及 '\'
' (單引號)。 數組
反斜槓加數字的形式 \ddd
來描述一個字符,注意,若是須要在這種描述方法後接一個是數字的字符, 那麼反斜槓後必須寫滿三個數字。閉包
下面五種方式描述了徹底相同的字符串:函數
a = 'alo\n123"' a = "alo\n123\"" a = '\97lo\10\04923"' a = [[alo 123"]] a = [==[ alo 123"]==]
Lua 中有八種基本類型: nil, boolean, number, string, function, userdata, thread, and table.lua
Boolean 類型只有兩種值:false 和 true。 nil 和 false 都能致使條件爲假;而另外全部的值都被看成真。spa
Number 表示實數(雙精度浮點數)。操作系統
userdata 類型用來將任意 C 數據保存在 Lua 變量中。 這個類型至關於一塊原生的內存,除了賦值和相同性判斷,Lua 沒有爲之預約義任何操做。 然而,經過使用 metatable (元表) ,程序員能夠爲 userdata 自定義一組操做。 userdata 不能在 Lua 中建立出來,也不能在 Lua 中修改。這樣的操做只能經過 C API。 這一點保證了宿主程序徹底掌管其中的數據。線程
thread 類型用來區別獨立的執行線程,它被用來實現 coroutine (協同例程)。 不要把 Lua 線程跟操做系統的線程搞混。 Lua 能夠在全部的系統上提供對 coroutine 的支持,即便系統並不支持線程。調試
table 類型實現了一個關聯數組。語言自己採用一種語法糖,支持以 a.name
的形式表示 a["name"]。
特別的,由於函數自己也是值,因此 table 的域中也能夠放函數。 這樣 table 中就能夠有一些 methods 了。
table, function ,thread ,和 (full) userdata 這些類型的值是所謂的對象: 變量自己並不會真正的存放它們的值,而只是放了一個對對象的引用。 賦值,參數傳遞,函數返回,都是對這些對象的引用進行操做; 這些操做不會作暗地裏作任何性質的拷貝。
Boolean 類型只有兩種值:false 和 true。 nil 和 false 都能致使條件爲假;而另外全部的值都被看成真。
Number 表示實數(雙精度浮點數)。
Lua 提供運行時字符串到數字的自動轉換。
全局變量,局部變量,還有 table 的域。
chunk :Lua 的一個執行單元被稱做 chunk。 一個 chunk 就是一串語句段,它們會被循序的執行。 每一個語句段能夠以一個分號結束。lua 把一個 chunk 看成一個擁有不定參數的匿名函數 (參見 §2.5.9)處理。 正是這樣,chunk 內能夠定義局部變量,接收參數,而且返回值。
賦值:賦值段首先會作運算完全部的表達式,而後僅僅作賦值操做。 所以,下面這段代碼
i = 3 i, a[i] = i+1, 20
會把 a[3]
設置爲 20,而不會影響到 a[4]
。 這是由於 a[i]
中的 i
在被賦值爲 4 以前就被拿出來了(那時是 3 )。 簡單說 ,這樣一行
x, y = y, x
能夠用來交換 x
和 y
中的值。
for 和 while:
for v = e1, e2, e3 do block end
用while表達:
do local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3) if not (var and limit and step) then error() end while (step > 0 and var <= limit) or (step <= 0 and var >= limit) do local v = var block var = var + step end end
注意:有個問題,for i=3,2,0 do print(i) end, 會進入死循環。
可變參數:函數調用和可變參數表達式均可以放在多重返回值中。 若是表達式做爲一個獨立語句段出現 (這隻能是一個函數調用), 它們的返回列表將被對齊到零個元素,也就是忽略全部返回值。 若是表達式用於表達式列表的最後(或者是惟一)的元素, 就不會有任何的對齊操做(除非函數調用用括號括起來)。 在任何其它的狀況下,Lua 將把表達式結果當作單一元素, 忽略除第一個以外的任何值。被括號括起來的表達式永遠被看成一個值。因此, (f(x,y,z))
即便 f
返回多個值,這個表達式永遠是一個單一值。 ((f(x,y,z))
的值是 f
返回的第一個值。若是 f
不返回值的話,那麼它的值就是 nil 。)
f() -- 調整到 0 個結果 g(f(), x) -- f() 被調整到一個結果 g(x, f()) -- g 被傳入 x 加上全部 f() 的返回值 a,b,c = f(), x -- f() 被調整到一個結果 ( c 在這裏被賦爲 nil ) a,b = ... -- a 被賦值爲可變參數中的第一個, -- b 被賦值爲第二個 (若是可變參數中並無對應的值, -- 這裏 a 和 b 都有可能被賦爲 nil) a,b,c = x, f() -- f() 被調整爲兩個結果 a,b,c = f() -- f() 被調整爲三個結果 return f() -- 返回 f() 返回的全部結果 return ... -- 返回全部從可變參數中接收來的值 return x,y,f() -- 返回 x, y, 以及全部 f() 的返回值 {f()} -- 用 f() 的全部返回值建立一個列表 {...} -- 用可變參數中的全部值建立一個列表 {f(), nil} -- f() 被調整爲一個結果
比較操做符:等於操做 (==
) 首先比較操做數的類型。 若是類型不一樣,結果就是 false。 不然,繼續比較值。 數字和字符串都用常規的方式比較。 對象 (table ,userdata ,thread ,以及函數)以引用的形式比較: 兩個對象只有在它們指向同一個東西時才認爲相等。 每次你建立一個新對象(一個 table 或是 userdata ,thread 函數), 它們都各不相同,即不一樣於上次建立的東西。
and, or, 以及 not:and要找一個假的,or要找一個真的,找到就返回;到最後也找不到就返回最後的元素。
10 or 20 --> 10 10 or error() --> 10 nil or "a" --> "a" nil and 10 --> nil false and error() --> false false and nil --> false false or nil --> nil 10 and 20 --> 20
操做符的優先級:寫在下表中,從低到高優先級排序:
or and < > <= >= ~= == .. + - * / % not # - (unary) ^
一般,能夠用括號來改變運算次序。 鏈接操做符 ('..
') 和冪操做 ('^
') 是從右至左的。 其它全部的操做都是從左至右。下面是一些例子:
print(false or 5 and 6) --> 6 print(false or 5 and nil) --> nil print(false or 2+3 >= 4*1 and not 7^2) --> false print(false or 2+3 >= 4*1 and not nil) --> true print(not nil) --> true print(false or nil) --> nil
經常使用卻不在乎的元方法:
"lt" 或是 "le":大小比較操做以如下方式進行。 若是參數都是數字,那麼就直接作數字比較。 不然,若是參數都是字符串,就用字符串比較的方式進行。 再則,Lua 就試着調用 "lt" 或是 "le" 元方法 。
concat:字符串的鏈接操做符寫做兩個點 ('..
')。 若是兩個操做數都是字符串或都是數字,鏈接操做將以 §2.2.1 中提到的規則把其轉換爲字符串。 不然,會取調用元方法 "concat"。
取長度操做符:寫做一元操做 #
。 字符串的長度是它的字節數(就是以一個字符一個字節計算的字符串長度)。
table t
的長度被定義成一個整數下標 n
。 它知足 t[n]
不是 nil 而 t[n+1]
爲 nil; 此外,若是 t[1]
爲 nil ,n
就多是零。 對於常規的數組,裏面從 1 到 n
放着一些非空的值的時候, 它的長度就精確的爲 n
,即最後一個值的下標。 若是數組有一個「空洞」 (就是說,nil 值被夾在非空值之間), 那麼 #t
多是任何一個是 nil 值的位置的下標 (就是說,任何一個 nil 值都有可能被當成數組的結束)。
語法糖:
表:a.name
的形式表示 a["name"];
函數: v:name(args)
這個樣子,被解釋成 v.name(v,args)
, 這裏 v
只會被求值一次。
函數:調用形式 f{fields}
是一種語法糖用於表示 f({fields})
; 這裏指參數列表是一個單一的新建立出來的列表;
函數:形式 f'string'
(或是 f"string"
亦或是 f[[string]]
) 也是一種語法糖,用於表示 f('string')
; 這裏指參數列表是一個單獨的字符串。
冒號語法能夠用來定義方法, 就是說,函數能夠有一個隱式的形參 self。 所以,以下寫法:
function t.a.b.c:f (params) body end
是這樣一種寫法的語法糖:
t.a.b.c.f = function (self, params) body end
簡化函數定義:
這樣的寫法:
function f () body end
被轉換成
f = function () body end
這樣的寫法:
function t.a.b.c.f () body end
被轉換成
t.a.b.c.f = function () body end
這樣的寫法:
local function f () body end
被轉換成
local f; f = function () body end
注意,並非轉換成
local f = function () body end
(這個差異只在函數體內須要引用 f 時纔有。)
尾調用:調用形式:return
functioncall 將觸發一個尾調用。 Lua 實現了適當的尾部調用(或是適當的尾遞歸): 在尾調用中, 被調用的函數重用調用它的函數的堆棧項。 所以,對於程序執行的嵌套尾調用的層數是沒有限制的。 然而,尾調用將刪除調用它的函數的任何調試信息。 注意,尾調用只發生在特定的語法下, 這時, return 只有單一函數調用做爲參數; 這種語法使得調用函數的結果能夠精確返回。 所以,下面這些例子都不是尾調用:
return (f(x)) -- 返回值被調整爲一個 return 2 * f(x) return x, f(x) -- 最加若干返回值 f(x); return -- 無返回值 return x or f(x) -- 返回值被調整爲一個
閉包:一個函數定義是一個可執行的表達式, 執行結果是一個類型爲 function 的值。 當 Lua 預編譯一個 chunk 的時候, chunk 做爲一個函數,整個函數體也就被預編譯了。 那麼,不管什麼時候 Lua 執行了函數定義, 這個函數自己就被實例化了(或者說是關閉了)。 這個函數的實例(或者說是closure(閉包)) 是表達式的最終值。 相同函數的不一樣實例有可能引用不一樣的外部局部變量, 也可能擁有不一樣的環境表。
形參,實參:當一個函數被調用, 若是函數沒有被定義爲接收不定長參數,即在形參列表的末尾註明三個點 ('...
'), 那麼實參列表就會被調整到形參列表的長度, 變長參數函數不會調整實參列表; 取而代之的是,它將把全部額外的參數放在一塊兒經過變長參數表達式傳遞給函數, 其寫法依舊是三個點。 這個表達式的值是一串實參值的列表,看起來就跟一個能夠返回多個結果的函數同樣。 若是一個變長參數表達式放在另外一個表達式中使用,或是放在另外一串表達式的中間, 那麼它的返回值就會被調整爲單個值。 若這個表達式放在了一系列表達式的最後一個,就不會作調整了(除非用括號給括了起來)。
咱們先作以下定義,而後再來看一個例子:
function f(a, b) end function g(a, b, ...) end function r() return 1,2,3 end
下面看看實參到形參數以及可變長參數的映射關係:
CALL PARAMETERS f(3) a=3, b=nil f(3, 4) a=3, b=4 f(3, 4, 5) a=3, b=4 f(r(), 10) a=1, b=10 f(r()) a=1, b=2 g(3) a=3, b=nil, ... --> (nothing) g(3, 4) a=3, b=4, ... --> (nothing) g(3, 4, 5, 8) a=3, b=4, ... --> 5 8 g(5, r()) a=5, b=1, ... --> 2 3
地方