%
操做符Lua 中的 %
操做符與 C 語言中的操做符雖然都是取模的含義,可是取模的方式不同。
在 C 語言中,取模操做是將兩個操做數的絕對值取模後,在添加上第一個操做數的符號。
而在 Lua 中,僅僅是簡單的對商相對負無窮向下取整後的餘數。javascript
+++java
在 C 中,閉包
a1 = abs(a); b1 = abs(b); c = a1 % b1 = a1 - floor(a1/b1)*b1; a % b = (a >= 0) ? c : -c;
在 Lua 中,函數
a % b == a - math.floor(a/b)*b
Lua 是直接根據取模定義進行運算。 C 則對取模運算作了一點處理。code
+++對象
舉例:blog
在 C 中ip
int a = 5 % 6; int b = 5 % -6; int c = -5 % 6; int d = -5 % -6; printf("a,b,c,d");--5,5,-5,-5
在 Lua 中內存
a = 5 % 6 b = 5 % -6 c = -5 % 6 d = -5 % -6 x = {a,b,c,d} for i,v in ipairs(x) do print(i,v) end --> 5 --> -1 --> 1 --> -5
能夠看到,僅當操做數同號時,兩種語言的取模結果相同。異號時,取模結果的符號與數值均不相等。字符串
在 Lua 中的取模運算總結爲:a % b,若是 a,b 同號,結果取 a,b 絕對值的模;異號,結果取 b 絕對值與絕對值取模後的差。取模後值的符號與 b 相同。
比較操做的結果是 boolean
型的,非 true
即 false
。
支持的操做符有:
< <= ~= == > >=
不支持 !
操做符。
+++
對於 ==
操做,運算時先比較兩個操做數的類型,若是不一致則結果爲 false。此時數值與字符串之間並不會自動轉換。
比較兩個對象是否相等時,僅當指向同一內存區域時,斷定爲 true
。·
a = 123 b = 233 c = "123" d = "123" e = {1,2,3} f = e g = {1,2,3} print(a == b) --> false print(a == c) --> false -- 數字與字符串做爲不一樣類型進行比較 print(c == d) --> true print(e == f) --> true -- 引用指向相同的對象 print(e == g) --> false -- 雖然內容相同,可是是不一樣的對象 print(false == nil) --> false -- false 是 boolean,nil 是 nil 型
方便標記,-->
表明前面表達式的結果。
+++
userdata
與 table
的比較方式能夠經過元方法 eq
進行改變。
大小比較中,數字和字符串的比較與 C 語言一致。若是是其餘類型的值,Lua會嘗試調用元方法 lt
和 le
。
and,or,not
僅認爲 false
與 nil
爲假。
not
取反操做 not
的結果爲 boolean
類型。(and
和 or
的結果則不必定爲 boolean
)
b = not a -- a 爲 nil,b 爲 true c = not not a -- c 爲 false
and
a and b
,若是 a
爲假,返回 a
,若是 a
爲真, 返回 b
。
注意,爲何 a
爲假的時候要返回 a
呢?有什麼意義?這是由於 a
多是 false
或者 nil
,這兩個值雖然都爲假,可是是有區別的。
or
a or b
,若是 a
爲假,返回 b
,若是 a
爲真, 返回 a
。與 and
相反。
+++
提示: 當邏輯操做符用於得出一個 boolean
型結果時,不須要考慮邏輯運算後返回誰的問題,由於邏輯操做符的操做結果符合本來的邏輯含義。
舉例
if (not (a > min and a < max)) then -- 若是 a 不在範圍內,則報錯 error() end
+++
and
與 or
遵循短路原則,第二個操做數僅在須要的時候會進行求值操做。
例子
a = 5 x = a or jjjj() -- 雖而後面的函數並無定義,可是因爲不會執行,所以不會報錯。 print(a) -->5 print(x) -->5
經過上面這個例子,咱們應當對於邏輯操做有所警覺,由於這可能會引入一些未能及時預料到的錯誤。
..
鏈接兩個字符串(或者數字)成爲新的字符串。對於其餘類型,調用元方法 concat
。
#
對於字符串,長度爲字符串的字符個數。
對於表,經過尋找知足t[n] 不是 nil 而 t[n+1] 爲 nil 的下標 n 做爲表的長度。
~~對於其餘類型呢?~~
-- 字符串取長 print(#"abc\0") --> 4 -- 表取長 print(#{[1]=1,[2]=2,[3]=3,x=5,y=6}) --> 3 print(#{[1]=1,[2]=nil,[3]=3,x=5,y=6}) --> 1
由低到高:
or and < > <= >= ~= == .. + - * / % not # - (unary) ^
冪運算>單目運算>四則運算>鏈接符>比較操做符>and>or
Table 構造的 BNF 定義
tableconstructor ::= `{´ [fieldlist] `}´ fieldlist ::= field {fieldsep field} [fieldsep] field ::= `[´ exp `]´ `=´ exp | Name `=´ exp | exp fieldsep ::= `,´ | `;´
BNF 定義參考 BNF範式簡介 。
舉例:
a = {} b = {["price"] = 5; cost = 4; 2+5} c = { [1] = 2+5, [2] = 2, 8, price = "abc", ["cost"] = 4} -- b 和 c 構造的表是等價的 print(b["price"]) --> 5 print(b.cost) --> 4 print(b[1]) --> 7 -- 未給出鍵值的,按序分配下標,下標從 1 開始 print(c["price"]) --> abc print(c.cost) --> 4 print(c[1]) --> 8 print(c[2]) --> 2
注意:
上面這兩條的存在使得上面的例子中 c1 的輸出值爲 8。
+++
若是表中有相同的鍵,那麼以靠後的那個值做爲鍵對應的值。
a = {[1] = 5,[1] = 6} -- 那麼 a[1] = 6
+++
若是表的最後一個域是表達式形式,而且是一個函數,那麼這個函數的全部返回值都會加入到表中。
a = 1 function order() a = a + 1 return 1,2,3,4 end b = {order(); a; order(); } c = {order(); a; (order());} print(b[1]) --> 1 print(b[2]) --> 2 -- 表中的值並非一次把表達式都計算結束後再賦值的 print(b[3]) --> 1 print(b[4]) --> 2 -- 表達式形式的多返回值函數 print(#b) --> 6 -- 表的長度爲 6 print(#c) --> 3 -- 函數添加括號後表的長度爲 3
函數是一個表達式,其值爲 function 類型的對象。函數每次執行都會被實例化。
Lua 中實現一個函數能夠有如下三種形式。
f = function() [block] end local f; f = function() [block] end a.f = function() [block] end
Lua 提供語法糖分別處理這三種函數定義。
function f() [block] end local function f() [block] end function a.f() [block] end
+++
上面 local
函數的定義之因此不是 local f = function() [block] end
,是爲了不以下錯誤:
local f = function() print("local fun") if i==0 then f() -- 編譯錯誤:attempt to call global 'f' (a nil value) i = i + 1 end end
形參會經過實參來初始化爲局部變量。
參數列表的尾部添加 ...
表示函數能接受不定長參數。若是尾部不添加,那麼函數的參數列表長度是固定的。
f(a,b) g(a,b,...) h(a,...,b) -- 編譯錯誤
f(1) --> a = 1, b = nil f(1,2) --> a = 1, b = 2 f(1,2,3) --> a = 1, b = 2 g(1,2) --> a = 1, b = 2, (nothing) g(1,2,3) --> a = 1, b = 2, (3) g(1,f(4,5),3) --> a = 1, b = 4, (3) g(1,f(4,5)) --> a = 1, b = 4, (5)
+++
還有一種形參爲self的函數的定義方式:
a.f = function (self, params) [block] end
其語法糖形式爲:
function a:f(params) [block] end
使用舉例:
a = {name = "唐衣可俊"} function a:f() print(self.name) end a:f() --> 唐衣可俊 -- 若是這裏使用 a.f(),那麼 self.name 的地方會報錯 attempt to index local 'self';此時應該寫爲 a.f(a)
:
的做用在於函數定義與調用的時候能夠少寫一個 self
參數。這種形式是對方法
的模擬
Lua 中的函數調用的BNF語法以下:
functioncall ::= prefixexp args
若是 prefixexp 的值的類型是 function, 那麼這個函數就被用給出的參數調用。 不然 prefixexp 的元方法 "call" 就被調用, call 的第一個參數就是 prefixexp 的值,接下來的是 args 參數列表(參見 2.8 元表 | Metatable)。
函數調用根據是否傳入 self
參數分爲 .
調用和 :
調用。
函數調用根據傳入參數的類型,能夠分爲參數列表調用、表調用、字符串調用。
[待完善]
若是一個函數訪問了它的外部變量,那麼它就是一個閉包。
因爲函數內部的變量均爲局部變量,外界沒法對其進行訪問。這時若是外界想要改變局部變量的值,那麼就可使用閉包來實現這一目的。
具體的實現過程大體是這樣,函數內部有可以改變局部變量的子函數,函數將這個子函數返回,那麼外界就能夠經過使用這個子函數來操做局部變量了。
例子:利用閉包來實現對局部變量進行改變
-- 實現一個迭代器 function begin(i) local cnt = i return function () -- 這是一個匿名函數,實現了自增的功能;同時它也是一個閉包,由於訪問了外部變量 cnt cnt = cnt + 1 return cnt end end iterator = begin(2) -- 設置迭代器的初值爲 2 ,返回一個迭代器函數 print(iterator()) -- 執行迭代 print(iterator())
提示: 關於閉包的更多說明可參考JavaScript 閉包是如何工做的?——StackOverflow
BNF範式簡介 (簡要介紹 BNF)
How do JavaScript closures work?——StackOverflow(詳細介紹了 Javascript 中閉包的概念)