腳本語言的基礎語法大都比較簡單,這裏只列舉一些lua獨有,或者須要特別注意的語法點。python
書中前三章的內容是一些慣常的引言,基礎數據類型,運算符等內容,相對簡單,這裏就再也不贅述。數組
一、do...end 能夠用來包含一個程序塊。安全
二、在循環語句中聲明的局部變量,在條件判斷時依然存在函數
三、for循環分爲數字型和泛型學習
數字型:lua
1 for var=exp1, exp2, exp3 do 2 <執行體> 3 end
相似於C中將括號和句號去掉,var初始值爲exp1,增加到exp2,步進爲exp3。spa
exp3可選,默認爲+1,不設上限可將exp2設置爲math.huge。翻譯
for的控制變量會被自動聲明爲for的局部變量,無需單獨聲明,同時也沒法在外部訪問。設計
泛型for:經過迭代器訪問table指針
1 for i,v in ipairs(a) do print(v) end -- 打印全部值 2 for k in pairs(t) do print(k) end -- 打印全部key
四、lua中提供多種迭代器,也可自行編寫
迭代文件中的行 io.lines
迭代table元素 pairs
迭代數組元素 ipairs
迭代字符串中單詞 string.gmatch
五、return ,break只能做爲代碼塊的最後一條語句,或是end,else,until前的最後一條語句,不然lua語法報錯,能夠經過 do return end 顯式包住一條return。
六、lua中函數,若只有一個參數,且該參數爲字面字符串或table構造式,函數的()能夠省略。
七、lua爲面向對象提供特殊語法——冒號操做符,將自己做爲第一個值傳入。
八、lua中函數能夠返回多個值,同時用多個變量接受,相似於多重賦值,可是若函數調用不是一系列表達式的最後一個值,則只產生一個值。
九、上一條中的現象,在多返回值函數做爲另外一個函數的非最後一個參數時也有效。
十、經過將函數調用放入一對圓括號中,能夠迫使其之返回一個值。
十一、unpack() 函數接受一個數組爲參數,而且從下標1逐個返回全部參數,經常使用於泛型調用。
十二、聲明函數時,參數爲(...),即爲變長參數,在函數中 ‘...’ 被看成表達式使用。
1三、變長參數和固定參數同時出如今函數參數中時,變長參數需放到最後。
1四、當變長參數中含有故意傳入的nil時,須要用select函數訪問,select函數首先必須傳入一個固定實參,若是這個實參爲數字n,那麼函數返回第n個變長參數(包括nil),不然變長參數必須爲‘#’,返回變長數的總和。
1五、具名函數,相似於python中指定函數參數賦值,可是須要把參數名和參數值寫到一個table中,傳入函數。
1六、lua中的函數爲第一類值,實際上將lua中的函數名理解爲一個持有函數的變量更爲合適。
1 function foo (x) return 2*x end 等價於 2 foo = function (x) return 2*x end
這使得lua能夠輕鬆實現回調模式,例如C++中STL提供的排序函數,須要傳入一個返回值爲bool類型的函數指針,用以比較容器變量的大小,lua中能夠這樣實現,
例如一個給table排序的函數:
1 network = {............} 2 table.sort(network, function (a, b) return (a.id > b.id) end)
對於這個特性的一個高階應用,求導數:
1 function derivative(f, delta) 2 delta = delta or 1e-4 3 return function(x) 4 return (f(x + delta) - f(x))/delta 5 end 6 end 7 8 c = derivate(math.sin) 9 print(math.cos(10), c(10)) 10 --> -0.83907152907645 -0.83904432662041
1七、closure(閉合函數),從翻譯上不太好理解這個概念。首先,在一個函數內部定義另外一個函數時,那麼內層的函數能夠訪問外層函數的變量,這項特徵被稱爲「詞法域」。而這個變量相對於內部的函數稱
爲「非局部的變量」,一個closure就是一個函數加上該函數所需訪問的全部非局部的變量。
1 function newCount() 2 local i = 0 3 return function() i = i + 1 return i end 4 end 5 6 c1 = newCount() 7 print(c1()) --> 1 8 print(c1()) --> 2 9 c2 = newCount() 10 print(c2()) --> 1 11 print(c1()) --> 3 12 print(c2()) --> 2
c1 和 c2是同一個函數所建立的兩個不一樣的closure,他們各自擁有局部變量i的實例。
1八、closure的另外一個用處是建立一個安全的沙盒環境去運行一些不受信任的代碼。
1 do 2 local oldOpen = oi.open 3 local access_OK = function(filename, mode) 4 <檢查訪問權限> 5 end 6 io.open = function(filename, mode) 7 if access_OK(filename, mode) then 8 return oldOpen(filename, mode) 9 else 10 return nil, "access denied" 11 end 12 end 13 end
1九、非全局函數,如某個table的成員或用local修飾了聲明的函數,只有在當前塊能夠訪問該函數。有一點須要注意,當定義遞歸的局部函數時,在遞歸時因爲局部的函數還沒有定義完畢,因此其實調用的是
一個同名的全局函數,能夠經過先定義一個局部的變量做爲函數名來解決這個問題。
20、對於非全局函數,lua中有一種語法糖:
1 local function foo(<參數>) <函數體> end
lua將其展開爲:
1 local foo 2 foo = function (<參數>) <函數體> end
這樣定義不會產生遞歸錯誤。固然對於間接遞歸這是無效的,間接遞歸必須一個前向聲明,示例代碼就不貼了,間接遞歸實在是種糟糕的語法,如非必要不要使用。
2一、尾調用,lua中正確的尾調用形式以下:
1 return <function>(<args>)
尾調用至關於一條goto語句,由於調用函數已經沒有須要執行的代碼,因此返回值能夠直接被被調函數,也就是尾調用的函數返回值覆蓋,此時遞歸的話不會產生棧溢出問題,同時也能夠利用lua的這一特
性實現狀態機,用尾調用跳轉到下一個狀態,不會出現任何內存問題。