?
This document uses PHP Chinese website manual Release
本節(jié)介紹 Lua 的詞匯,語法和語義。換句話說,本節(jié)描述哪些標記是有效的,它們?nèi)绾谓M合以及它們的組合意味著什么。
將使用通常的擴展BNF符號來解釋語言構造,其中{ a }表示0或更多a,并且a表示可選的a。非終端顯示為非終端,關鍵字顯示為kword,其他終端符號顯示為' = '。Lua的完整語法可以在本手冊末尾的§9中找到。
Lua 是一種自由形式的語言。它忽略空格(包括新行)和詞法元素(標記)之間的注釋,除了名稱和關鍵字之間的分隔符。
Lua中的名稱(也稱為標識符)可以是任何字母,數(shù)字和下劃線的字符串,不是以數(shù)字開始,也不是保留字。標識符用于命名變量,表格字段和標簽。
以下關鍵字是保留的,不能用作名稱:
and break do else elseif endfalse for function goto if inlocal nil not or repeat returnthen true until while
Lua是一種區(qū)分大小寫的語言:并且是一個保留字,但And和AND是兩個不同的有效名稱。 作為慣例,程序應該避免創(chuàng)建以下劃線開頭的名稱,后跟一個或多個大寫字母(例如_VERSION)。
以下字符串表示其他令牌:
+ - * / % ^ #& ~ | << >> //== ~= <= >= < > =( ) { } [ ] ::; : , . .. ...
甲短文本字符串可以通過匹配單引號或雙引號進行分隔,并且可以包含下面的C狀的轉義序列:“ \a
”(鐘形),“ \b
”(退格),“ \f
”(形式進料),“ \n
”(換行), ' \r
'(回車符),' \t
'(水平制表符),' \v
'(垂直制表符),' \\
'(反斜杠),' \"
'(引號雙引號)和' \'
'(撇號單引號)。反斜杠后跟換行符會導致字符串中出現(xiàn)換行符。轉義序列'\z
'跳過以下的空白字符,包括換行符; 將長文字字符串分割并縮進多行而不將新行和空格添加到字符串內(nèi)容中特別有用。一個簡短的文字字符串不能包含未轉義的換行符,也不能包含不構成有效轉義序列的轉義符。
我們可以通過數(shù)字值(包括嵌入的零)在短文字字符串中指定任何字節(jié)。這可以通過轉義序列來完成\xXX
,其中XX是正好兩個十六進制數(shù)字的序列,或者是轉義序列\ddd
,其中ddd是最多三位十進制數(shù)字的序列。(請注意,如果十進制轉義序列后跟一個數(shù)字,則必須使用三位數(shù)字表示。)
Unicode字符的UTF-8編碼可以用轉義序列(注意強制括號括起來)插入到一個文字字符串中,其中XXX是一個代表字符代碼點的一個或多個十六進制數(shù)字的序列。\u{
XXX
}
文字字符串也可以使用由長括號括起來的長格式來定義。我們定義了一個開放的n級開放長方括號作為開放方括號,其后是n等號,然后是另一個開放方括號。因此,0級[[
開放長括號寫為[=[
,1級開放長括號寫為,等等。甲長括號被類似地定義; 例如,第4級的一個結束長括號寫為]====]
。一個長的文字從任何級別的開放式長支架開始,到同級別的第一個長支架結束。它可以包含除了相同級別的右括號之外的任何文本。括號內(nèi)的文字可以運行多行,不解釋任何轉義序列,并忽略任何其他級別的長括號。任何類型的行尾順序(回車符,換行符,回車符后跟換行符,或換行符后接回車符)都會轉換為簡單的換行符。
為方便起見,當開頭的長括號緊跟著一個換行符時,換行符不包含在字符串中。例如,在使用ASCII的系統(tǒng)中(其中' a
'編碼為97,新行編碼為10,' 1
'編碼為49),下面的五個字符串表示相同的字符串:
a = 'alo\n123"'a = "alo\n123\""a = '\97lo\10\04923"'a = [[alo123"]]a = [==[alo123"]==]
未受前面規(guī)則明確影響的文字字符串中的任何字節(jié)代表自身。但是,Lua會以文本模式打開文件進行解析,并且系統(tǒng)文件功能可能會對某些控制字符產(chǎn)生問題。因此,將非文本數(shù)據(jù)表示為帶有非文本字符的顯式轉義序列的引用文本更安全。
一個數(shù)字常量(或數(shù)字)可以用一個可選的小數(shù)部分和一個可選的小數(shù)指數(shù)來編寫,用一個字母' e
'或' E
' 標記。Lua也接受以0x
或開頭的十六進制常量0X
。十六進制常量還接受可選的小數(shù)部分加上可選的二進制指數(shù),用字母p
“或” 標記P
。帶小數(shù)點或指數(shù)的數(shù)字常量表示浮點數(shù); 否則,如果它的值適合整數(shù),它表示一個整數(shù)。有效的整數(shù)常量的例子是
3 345 0xff 0xBEBADA
Examples of valid float constants are
3.0 3.1416 314.16e-2 0.31416E1 34e10x0.1E 0xA23p-4 0X1.921FB54442D18P+1
一個注釋開始用雙連字符(--
)的字符串以外的任何地方。如果緊接著的文本--
不是開頭的長括號,則注釋是一個簡短的注釋,直到行尾。否則,這是一個很長的評論,一直運行到相應的結束長支架。經(jīng)常使用長注釋來臨時禁用代碼。
變量是存儲值的地方。Lua中有三種變量:全局變量,局部變量和表格字段。
一個名稱可以表示一個全局變量或一個局部變量(或一個函數(shù)的形式參數(shù),它是一種特殊的局部變量):
var ::= Name
名稱表示標識符,如§3.1所定義。
除非明確聲明為局部變量,否則假定任何變量名都是全局變量(見§3.3.7)。局部變量在詞匯范圍內(nèi):局部變量可以通過其范圍內(nèi)定義的函數(shù)自由訪問(請參閱第3.5節(jié))。
在第一次賦值給變量之前,其值為空。
方括號用于索引表:
var ::= prefixexp ‘[’ exp ‘]’
訪問表格字段的含義可以通過metatables來更改。對索引變量的訪問t[i]
相當于一個調(diào)用gettable_event(t,i)
。(關于gettable_event
函數(shù)的完整描述,請參閱§2.4,這個函數(shù)在Lua中沒有定義或調(diào)用,我們在這里使用它只是為了說明的目的。)
語法var.Name
只是語法糖var["Name"]
:
var ::= prefixexp ‘.’ Name
對全局變量的訪問x
等同于_ENV.x
。由于塊被編譯的方式,_ENV
永遠不會是一個全局名稱(見§2.2)。
Lua支持幾乎常規(guī)的語句集,類似于Pascal或C語言中的語句集。該集包括賦值,控制結構,函數(shù)調(diào)用和變量聲明。
塊是一系列語句,按順序執(zhí)行:
block ::= {stat}
Lua具有空語句,允許您用分號分隔語句,用分號開始塊或按順序寫兩個分號:
stat ::= ‘;’
函數(shù)調(diào)用和賦值可以從左括號開始。這種可能性導致了Lua語法中的模糊性??紤]下面的片段:
a = b + c(print or io.write)('done')
語法可以通過兩種方式看到它:
a = b + c(print or io.write)('done')a = b + c; (print or io.write)('done')
當前的解析器總是以第一種方式看到這樣的構造,將左括號解釋為調(diào)用參數(shù)的開始。為避免這種歧義,最好總是使用以括號開頭的分號語句:
;(print or io.write)('done')
一個塊可以被明確地分隔以產(chǎn)生單個語句:
stat ::= do block end
顯式塊用于控制變量聲明的范圍。顯式塊有時也用于在另一個塊的中間添加return語句(請參閱第3.3.4節(jié))。
Lua 的編譯單位被稱為一個塊。在語法上,塊只是一個塊:
chunk ::= block
Lua 將塊作為具有可變數(shù)量參數(shù)的匿名函數(shù)的主體來處理 (請參閱第3.4.11節(jié))。因此,塊可以定義局部變量,接收參數(shù)和返回值。而且,這樣的匿名函數(shù)被編譯為一個外部局部變量的范圍_ENV
(參見§2.2)。得到的函數(shù)總是具有_ENV
唯一的upvalue,即使它不使用該變量。
塊可以存儲在主機程序中的文件或字符串中。為了執(zhí)行塊,Lua首先加載它,將塊的代碼預編譯為虛擬機的指令,然后Lua使用虛擬機的解釋器執(zhí)行編譯的代碼。
塊也可以預編譯成二進制形式; 詳情請參閱程序luac
和功能string.dump
。源代碼和編譯形式的程序是可以互換的; Lua會自動檢測文件類型并相應地執(zhí)行操作(請參閱load
)。
Lua 允許多個分配。因此,賦值語法定義了左側的變量列表和右側的表達式列表。兩個列表中的元素用逗號分隔:
stat ::= varlist ‘=’ explist varlist ::= var {‘,’ var}explist ::= exp {‘,’ exp}
表達式在§3.4中討論。
在賦值之前,將值列表調(diào)整為變量列表的長度。如果有更多的值超出需要,超出的值將被丟棄。如果有少于所需的值,該列表將被盡可能多的零的需要。如果表達式列表以一個函數(shù)調(diào)用結束,那么在調(diào)整之前,該調(diào)用返回的所有值都會輸入值列表(除非調(diào)用被括在圓括號中;請參閱第3.4節(jié))。
賦值語句首先評估其所有表達式,然后才執(zhí)行賦值。這樣的代碼
i = 3i, a[i] = i+1, 20
設置a[3]
為20,不會影響,a[4]
因為i
在a[i]
分配4之前,對in 進行評估(至3)。同樣,該行
x, y = y, x
交換x
和y
,和的值
x, y, z = y, z, x
周期性的置換的值x
,y
和z
。
賦值給全局變量和表字段的含義可以通過metatables來改變。對索引變量的分配t[i] = val
等同于settable_event(t,i,val)
。(關于settable_event
函數(shù)的完整描述,請參閱§2.4,這個函數(shù)在Lua中沒有定義或調(diào)用,我們在這里使用它只是為了說明的目的。)
對全局名稱x = val
的分配等同于分配_ENV.x = val
(請參閱第2.2節(jié))。
控制結構if,while,and repeat具有通常的含義和熟悉的語法:
stat ::= while exp do block end stat ::= repeat block until exp stat ::= if exp then block {elseif exp then block} [else block] end
Lua 中也有一個用于說法,兩種口味(見§3.3.5)。
控件結構的條件表達式可以返回任何值。這兩種假和零被認為是假的。所有與nil和false不同的值都被認為是真的(特別是數(shù)字0和空字符串也是如此)。
在repeat - until循環(huán)中,內(nèi)部塊不會以until關鍵字結束,而只會在條件之后結束。所以,條件可以引用循環(huán)塊中聲明的局部變量。
將跳轉語句將程序控制的標簽。出于語法原因,Lua中的標簽也被認為是語句:
stat ::= goto Name stat ::= label label ::= ‘::’ Name ‘::’
在定義標簽的整個塊中都可以看到標簽,除了嵌套塊中定義了標簽名稱相同的嵌套塊以及嵌套函數(shù)內(nèi)部的標簽。只要不進入局部變量的范圍,goto可以跳轉到任何可見標簽。
標簽和空語句被稱為空語句,因為它們不執(zhí)行任何操作。
在休息的語句終止執(zhí)行,同時,重復,或用于循環(huán),跳到循環(huán)之后的下一條語句:
stat ::= break
休息結束該最內(nèi)層循環(huán)。
該返回語句用來從一功能或一組塊(這是一個匿名功能)返回值。函數(shù)可以返回多個值,所以return語句的語法是
stat ::= return [explist] [‘;’]
在返回語句只能寫成塊的最后陳述。如果真的有必要在塊的中間返回,那么可以使用一個明確的內(nèi)部塊,就像在成語中一樣do return end
,因為現(xiàn)在return是它的(內(nèi)部)塊中的最后一個語句。
該對語句有兩種形式:一個數(shù)字和一個通用的。
數(shù)值為同時控制變量通過算術級數(shù)運行循環(huán)重復的代碼塊。它具有以下語法:
stat ::= for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end
該塊從第一個exp的值開始重復名稱,直到它通過第三個exp的步驟傳遞第二個exp。更確切地說,一個for語句就像
for v = e1, e2, e3 do block end
相當于代碼:
do local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3) if not (var and limit and step) then error() end var = var - step while true do var = var + step if (step >= 0 and var > limit) or (step < 0 and var < limit) then break end local v = var block end end
請注意以下幾點:
在循環(huán)開始之前,所有三個控制表達式都只計算一次。他們都必須得到數(shù)字。
var
,limit
并且step
是不可見的變量。此處顯示的名稱僅用于解釋目的。
如果第三個表達式(步驟)不存在,則使用1的步驟。
你可以使用break和goto來退出for循環(huán)。
循環(huán)變量v
是循環(huán)體的局部變量。如果循環(huán)后需要它的值,則在退出循環(huán)之前將其分配給另一個變量。
通用的聲明在工作職能,叫做迭代器。在每次迭代時,調(diào)用迭代器函數(shù)以產(chǎn)生一個新值,當新值為零時停止。泛型for循環(huán)具有以下語法:
stat ::= for namelist in explist do block end namelist ::= Name {‘,’ Name}
一個for語句像
for var_1, ···, var_n in explist do block end
相當于代碼:
do local f, s, var = explist while true do local var_1, ···, var_n = f(s, var) if var_1 == nil then break end var = var_1 block end end
請注意以下幾點:
explist
只評估一次。其結果是第一個迭代器變量的迭代器函數(shù),狀態(tài)和初始值。
f
,s
并且var
是不可見的變量。這些名字只是為了解釋的目的。
您可以使用break來退出for循環(huán)。
循環(huán)變量對于循環(huán)var_i
是局部的; 之后,你不能用自己的價值觀為目的。如果您需要這些值,則在分解或退出循環(huán)之前將它們分配給其他變量。
為了允許可能的副作用,函數(shù)調(diào)用可以作為語句來執(zhí)行:
stat ::= functioncall
在這種情況下,所有返回的值都會被丟棄。函數(shù)調(diào)用在§3.4.10中解釋。
局部變量可以在塊內(nèi)的任何地方聲明。聲明可以包括一個初始任務:
stat ::= local namelist [‘=’ explist]
如果存在,初始分配與多重分配具有相同的語義(見§3.3.3)。否則,所有變量都用nil初始化。
一個塊也是一個塊(見§3.3.2),因此局部變量可以在任何顯式塊外的塊中聲明。
局部變量的可見性規(guī)則在§3.5中解釋。
Lua 中的基本表達式如下:
exp ::= prefixexp exp ::= nil | false | trueexp ::= Numeral exp ::= LiteralString exp ::= functiondef exp ::= tableconstructor exp ::= ‘...’ exp ::= exp binop exp exp ::= unop exp prefixexp ::= var | functioncall | ‘(’ exp ‘)’
數(shù)字和文字字符串在§3.1中解釋; 變量在§3.2中解釋; 函數(shù)定義在§3.4.11中解釋; 函數(shù)調(diào)用在§3.4.10中解釋; 表的構造函數(shù)在§3.4.9中有解釋。Vararg表達式由三個點(' ...
')表示,只能在可變參數(shù)函數(shù)內(nèi)直接使用; 他們在§3.4.11中有解釋。
二進制運算符包括算術運算符(見§3.4.1),位運算符(見§3.4.2),關系運算符(見§3.4.4),邏輯運算符(見§3.4.5)和連接運算符(見§§3.4.5) 3.4.6)。一元運算符包括一元減號(見§3.4.1),一元位運算NOT(見§3.4.2),一元邏輯not(見§3.4.5)和一元運算符(見§3.4.7) 。
函數(shù)調(diào)用和可變參數(shù)表達式可能會導致多個值。如果函數(shù)調(diào)用被用作語句(參見§3.3.6),那么它的返回列表被調(diào)整為零個元素,從而丟棄所有返回的值。如果表達式用作表達式列表的最后一個(或唯一)元素,則不會進行調(diào)整(除非表達式用圓括號括起來)。在所有其他情況下,Lua會將結果列表調(diào)整為一個元素,要么丟棄除第一個元素之外的所有值,要么在沒有值的情況下添加單個零。
這里有些例子:
f() -- adjusted to 0 resultsg(f(), x) -- f() is adjusted to 1 resultg(x, f()) -- g gets x plus all results from f()a,b,c = f(), x -- f() is adjusted to 1 result (c gets nil)a,b = ... -- a gets the first vararg parameter, b gets -- the second (both a and b can get nil if there -- is no corresponding vararg parameter)a,b,c = x, f() -- f() is adjusted to 2 results a,b,c = f() -- f() is adjusted to 3 resultsreturn f() -- returns all results from f()return ... -- returns all received vararg parametersreturn x,y,f() -- returns x, y, and all results from f(){f()} -- creates a list with all results from f(){...} -- creates a list with all vararg parameters{f(), nil} -- f() is adjusted to 1 result
括在括號中的任何表達式總是只會導致一個值。因此,(f(x,y,z))
即使f
返回多個值,也始終是單個值。(如果不返回任何值,則(f(x,y,z))
返回的值是f
或nilf
。)
Lua 支持以下算術運算符:
+
: addition
-
: subtraction
*
: multiplication
/
: float division
//
: floor division
%
: modulo
^
: exponentiation
-
: unary minus
除了冪乘和浮點除法之外,算術運算符的工作方式如下:如果兩個操作數(shù)都是整數(shù),則操作將在整數(shù)上執(zhí)行,結果為整數(shù)。否則,如果兩個操作數(shù)都是可以轉換為數(shù)字的數(shù)字或字符串(請參閱第3.4.3節(jié)),那么它們將轉換為浮點數(shù),操作按照通常的浮點算法規(guī)則執(zhí)行(通常是IEEE 754標準) ,結果是浮動。
指數(shù)/
運算和浮點除法()總是將它們的操作數(shù)轉換為浮點數(shù),結果總是浮點數(shù)。指數(shù)pow
運算使用ISO C函數(shù),因此它也適用于非整數(shù)指數(shù)。
Floor division(//
)是一個將商朝向負無窮大的部分,即其操作數(shù)分區(qū)的底部。
模數(shù)被定義為將商朝向負無窮(地板分割)四舍五入的分割的其余部分。
在整數(shù)算術中溢出的情況下,根據(jù)通常的雙補數(shù)算法規(guī)則,所有的操作都會回繞。(換句話說,它們返回等于模264的唯一可表示的整數(shù)到數(shù)學結果。)
Lua 支持以下按位運算符:
&
: bitwise AND
|
: bitwise OR
~
: bitwise exclusive OR
>>
: right shift
<<
: left shift
~
: unary bitwise NOT
所有按位操作都將其操作數(shù)轉換為整數(shù)(請參閱第3.4.3節(jié)),對這些整數(shù)的所有位進行操作,并生成一個整數(shù)。
右移和左移用零填充空位。負位移轉向另一個方向; 絕對值等于或大于整數(shù)位數(shù)的位移結果為零(所有位都移出)。
Lua 在運行時提供了一些類型和表示之間的自動轉換。按位運算符總是將浮點操作數(shù)轉換為整數(shù)。指數(shù)運算和浮點除法總是將整數(shù)運算符轉換為浮點數(shù)。應用于混合數(shù)字(整數(shù)和浮點數(shù))的所有其他算術運算將整數(shù)操作數(shù)轉換為浮點數(shù); 這被稱為通常的規(guī)則。根據(jù)需要,C API也將這兩個整數(shù)轉換為浮點數(shù)并浮點到整數(shù)。而且,字符串連接除了字符串之外還接受數(shù)字作為參數(shù)。
只要有數(shù)字,Lua 也會將字符串轉換為數(shù)字。
在從整數(shù)到浮點數(shù)的轉換中,如果整數(shù)值具有精確的浮點形式,那就是結果。否則,轉換得到最接近的較高或最接近較低的可表示值。這種轉換永遠不會失敗。
從float到integer的轉換檢查浮點數(shù)是否具有精確表示形式(即浮點數(shù)是整數(shù)值并且處于整數(shù)表示范圍內(nèi))。如果是這樣,那就是結果。否則,轉換失敗。
從字符串到數(shù)字的轉換過程如下:首先,將字符串轉換為整數(shù)或浮點數(shù),遵循其語法和Lua詞法分析器的規(guī)則。(該字符串可能還有前導空格和尾隨空格以及符號)。然后,結果數(shù)字(浮點數(shù)或整數(shù))轉換為上下文所需的類型(浮點型或整數(shù)型)(例如強制轉換的操作)。
從字符串到數(shù)字的所有轉換都接受點和當前語言環(huán)境標記作為基數(shù)字符。(然而,Lua詞法分析器只接受一個點。)
從數(shù)字到字符串的轉換使用非指定的可讀格式。要完全控制數(shù)字如何轉換為字符串,請使用format
字符串庫中的函數(shù)(請參閱參考資料string.format
)。
Lua 支持以下關系運算符:
==
: 平等
~=
:不平等
<
: 少于
>
: 比...更棒
<=
:少或相等
>=
:大于或等于
這些操作員總是導致錯誤或真實。
Equality(==
)首先比較其操作數(shù)的類型。如果類型不同,那么結果是錯誤的。否則,將比較操作數(shù)的值。字符串以明顯的方式進行比較。如果數(shù)字表示相同的數(shù)學值,則數(shù)字相等。
表,用戶數(shù)據(jù)和線程按引用進行比較:只有兩個對象是相同的對象時,才認為兩個對象相等。每次創(chuàng)建一個新對象(一個表,用戶數(shù)據(jù)或線程)時,這個新對象都不同于任何先前存在的對象。具有相同參考的閉包總是相同的。任何可檢測到的差異(不同行為,不同定義)的閉包總是不同的。
您可以通過使用“eq”元方法來更改Lua比較表和用戶數(shù)據(jù)的方式(請參閱第2.4節(jié))。
平等比較不會將字符串轉換為數(shù)字,反之亦然。因此,"0"==0
計算結果為假,并t[0]
和t["0"]
在表中表示不同的條目。
運算符~=
恰恰是否定平等(==
)。
訂單操作員的工作如下。如果兩個參數(shù)都是數(shù)字,則根據(jù)它們的數(shù)學值(不管它們的子類型)進行比較。否則,如果兩個參數(shù)都是字符串,則根據(jù)當前語言環(huán)境比較它們的值。否則,Lua會嘗試調(diào)用“l(fā)t”或“l(fā)e”元方法(請參閱第2.4節(jié))。比較結果a > b
被翻譯b < a
并a >= b
翻譯成b <= a
。
按照IEEE 754標準,NaN被認為既不小于也不等于也不大于任何值(包括其本身)。
Lua中的邏輯運算符是和,或者,而不是。像控制結構一樣(參見§3.3.4),所有邏輯運算符都將false和nil都視為false,其他都視為true。
否定運算符不總是返回false或true。如果該值為false或nil,則該聯(lián)合運算符并返回其第一個參數(shù); 否則,并返回其第二個參數(shù)。如果此值與nil和false不同,則該分離運算符或返回其第一個參數(shù); 否則,或返回其第二個參數(shù)。既與和或使用短路評價; 也就是說,第二個操作數(shù)僅在必要時才被評估。這里有些例子:
10 or 20 --> 1010 or error() --> 10nil or "a" --> "a"nil and 10 --> nilfalse and error() --> falsefalse and nil --> falsefalse or nil --> nil10 and 20 --> 20
(在本手冊中,-->
表示前面表達式的結果。)
Lua 中的字符串連接運算符用兩個點(' ..
')表示。如果兩個操作數(shù)都是字符串或數(shù)字,則根據(jù)§3.4.3中描述的規(guī)則將它們轉換為字符串。否則,__concat
metamethod被稱為(見§2.4)。
長度運算符由一元前綴運算符表示#
。
字符串的長度是其字節(jié)數(shù)(即每個字符為一個字節(jié)時字符串長度的常用含義)。
應用于表格的長度運算符在該表格中返回邊框。表中的邊框t
是滿足以下條件的任何自然數(shù):
(border == 0 or t[border] ~= nil) and t[border + 1] == nil
換言之,邊界是表中任何(自然)索引,其中非零值后面跟著零值(或當索引1為零時為零)。
只有一個邊界的表格稱為序列。例如,表格{10, 20, 30, 40, 50}
是一個序列,因為它只有一個邊界(5)。該表{10, 20, 30, nil, 50}
有兩個邊界(3和5),因此它不是一個序列。該表{nil, 20, 30, nil, nil, 60, nil}
有三個邊界(0,3和6),所以它也不是一個序列。該表{}
是一個邊界為0的序列。請注意,非自然鍵不會影響表是否為序列。
何時t
是序列,#t
返回其唯一邊界,這對應于序列長度的直觀概念。何時t
不是序列,#t
可以返回其任何邊界。(確切的依賴于表的內(nèi)部表示的細節(jié),這又取決于表的填充方式以及非數(shù)字鍵的內(nèi)存地址。)
表的長度的計算具有保證的最差時間O(log n),其中n是表中最大的自然鍵。
程序可以通過元方法修改長度運算符的任何值的行為,但字符串__len
(見§2.4)。
Lua 中的運算符優(yōu)先級遵循下表,從低優(yōu)先級到高優(yōu)先級:
or and< > <= >= ~= ==|~&<< >>..+ -* / // %unary operators (not # - ~)^
像往常一樣,您可以使用圓括號來更改表達式的優(yōu)先順序。串聯(lián)(' ..
')和求冪(' ^
')操作符是正確的關聯(lián)。所有其他二元運算符都是關聯(lián)的。
表構造函數(shù)是創(chuàng)建表的表達式。每次評估構造函數(shù)時,都會創(chuàng)建一個新表。構造函數(shù)可用于創(chuàng)建空表或創(chuàng)建表并初始化其某些字段。構造函數(shù)的一般語法是
tableconstructor ::= ‘{’ [fieldlist] ‘}’ fieldlist ::= field {fieldsep field} [fieldsep]field ::= ‘[’ exp ‘]’ ‘=’ exp | Name ‘=’ exp | exp fieldsep ::= ‘,’ | ‘;’
表單的每個字段都會[exp1] = exp2
向新表添加一個包含鍵exp1
和值的條目exp2
。該表單的字段name = exp
等同于["name"] = exp
。最后,表單字段exp
相當于[i] = exp
,在那里i
與1中的其他格式字段開始不影響此計數(shù)連續(xù)整數(shù)。例如,
a = { [f(1)] = g; "x", "y"; x = 1, f(x), [30] = 23; 45 }
相當于
do local t = {} t[f(1)] = g t[1] = "x" -- 1st exp t[2] = "y" -- 2nd exp t.x = 1 -- t["x"] = 1 t[3] = f(x) -- 3rd exp t[30] = 23 t[4] = 45 -- 4th exp a = t end
構造函數(shù)中賦值的順序是未定義的。(這個命令只有當有重復的鍵時才有意義。)
如果列表中的最后一個字段具有形式exp
,而表達式是函數(shù)調(diào)用或可變參數(shù)表達式,則此表達式返回的所有值都會連續(xù)進入列表(請參閱第3.4.10節(jié))。
為了方便機器生成的代碼,字段列表可以有一個可選的尾隨分隔符。
Lua中的函數(shù)調(diào)用具有以下語法:
functioncall ::= prefixexp args
在函數(shù)調(diào)用中,第一個prefixexp和args被評估。如果prefixexp的值具有類型函數(shù),則使用給定的參數(shù)調(diào)用此函數(shù)。否則,調(diào)用prefixexp“call”metamethod,將prefixexp的值作為第一個參數(shù),然后是原始調(diào)用參數(shù)(請參閱第2.4節(jié))。
表格
functioncall ::= prefixexp ‘:’ Name args
可以用來調(diào)用“方法”。一個調(diào)用是語法糖,除了只評估一次。v:name(args)v.name(v,args)v
參數(shù)具有以下語法:
args ::= ‘(’ [explist] ‘)’ args ::= tableconstructor args ::= LiteralString
在調(diào)用之前評估所有參數(shù)表達式。形式的調(diào)用是語法糖; 也就是說,參數(shù)列表是一個新的表格。形式(或或)的調(diào)用是語法糖; 也就是說,參數(shù)列表是一個單一的文字字符串。f{fields}f({fields})f'string'f"string"f[[string]]f('string')
表格的呼叫return
functioncall
稱為尾部呼叫。Lua實現(xiàn)適當?shù)奈膊空{(diào)用(或適當?shù)奈膊窟f歸):在尾部調(diào)用中,被調(diào)用函數(shù)重用調(diào)用函數(shù)的堆棧條目。因此,程序可以執(zhí)行的嵌套尾調(diào)用的數(shù)量沒有限制。但是,尾部調(diào)用將刪除有關調(diào)用函數(shù)的任何調(diào)試信息。請注意,尾部調(diào)用僅在特定語法時發(fā)生,其中返回有一個函數(shù)調(diào)用作為參數(shù); 這個語法使得調(diào)用函數(shù)完全返回被調(diào)用函數(shù)的返回值。所以,下面的例子都不是尾調(diào)用:
return (f(x)) -- results adjusted to 1return 2 * f(x)return x, f(x) -- additional resultsf(x); return -- results discardedreturn x or f(x) -- results adjusted to 1
函數(shù)定義的語法是
functiondef ::= function funcbody funcbody ::= ‘(’ [parlist] ‘)’ block end
以下語法糖簡化了函數(shù)定義:
stat ::= function funcname funcbody stat ::= local function Name funcbody funcname ::= Name {‘.’ Name} [‘:’ Name]
該聲明
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
(當函數(shù)的主體包含引用時,這只會有所不同f
。)
函數(shù)定義是一個可執(zhí)行表達式,其值具有類型函數(shù)。當Lua預編譯一個塊時,它的所有函數(shù)體也被預編譯。然后,每當Lua執(zhí)行函數(shù)定義時,函數(shù)就會被實例化(或關閉)。該函數(shù)實例(或閉包)是表達式的最終值。
參數(shù)作為使用參數(shù)值初始化的局部變量:
parlist ::= namelist [‘,’ ‘...’] | ‘...’
當函數(shù)被調(diào)用時,參數(shù)列表被調(diào)整為參數(shù)列表的長度,除非該函數(shù)是一個可變參數(shù)函數(shù),...
在參數(shù)列表末尾用三個點(' ')表示。變量函數(shù)不調(diào)整其參數(shù)列表; 相反,它收集所有額外的參數(shù)并通過可變參數(shù)表達式將它們提供給函數(shù),這也寫成三個點。此表達式的值是所有實際額外參數(shù)的列表,類似于具有多個結果的函數(shù)。如果在另一個表達式中或在表達式列表中使用可變表達式,則將其返回列表調(diào)整為一個元素。如果表達式用作表達式列表的最后一個元素,則不作調(diào)整(除非最后一個表達式括在圓括號中)。
作為例子,請考慮以下定義:
function f(a, b) endfunction g(a, b, ...) endfunction r() return 1,2,3 end
然后,我們有以下從參數(shù)到參數(shù)和可變參數(shù)表達式的映射:
CALL PARAMETERSf(3) a=3, b=nilf(3, 4) a=3, b=4f(3, 4, 5) a=3, b=4f(r(), 10) a=1, b=10f(r()) a=1, b=2g(3) a=3, b=nil, ... --> (nothing)g(3, 4) a=3, b=4, ... --> (nothing)g(3, 4, 5, 8) a=3, b=4, ... --> 5 8g(5, r()) a=5, b=1, ... --> 2 3
結果使用return語句返回(請參閱第3.3.4節(jié))。如果控件在沒有遇到return語句的情況下到達函數(shù)的結尾,則函數(shù)返回而沒有結果。
對函數(shù)可能返回的值的數(shù)量有一個與系統(tǒng)相關的限制。這個限制保證大于1000。
在結腸語法用于定義方法,即,具有一個隱含的額外的參數(shù)的功能self
。因此,聲明
function t.a.b.c:f (params) body end
是句法糖的
t.a.b.c.f = function (self, params) body end
Lua 是一個詞匯范圍的語言。局部變量的范圍從聲明后的第一個語句開始,一直持續(xù)到包含聲明的最內(nèi)層塊的最后一個非 void 語句??紤]下面的例子:
x = 10 -- global variabledo -- new block local x = x -- new 'x', with value 10 print(x) --> 10 x = x+1 do -- another block local x = x+1 -- another 'x' print(x) --> 12 end print(x) --> 11endprint(x) --> 10 (the global one)
請注意,在一個聲明中local x = x
,聲明的新x
聲明尚未包含在范圍內(nèi),因此第二個聲明是x
外部變量。
由于詞匯范圍規(guī)則,局部變量可以通過其范圍內(nèi)定義的函數(shù)自由訪問。內(nèi)部函數(shù)使用的局部變量在內(nèi)部函數(shù)內(nèi)被稱為upvalue或外部局部變量。
注意每個本地語句的執(zhí)行定義了新的局部變量??紤]下面的例子:
a = {}local x = 20for i=1,10 do local y = 0 a[i] = function () y=y+1; return x+y end end
該循環(huán)創(chuàng)建十個閉包(即,匿名函數(shù)的十個實例)。每個關閉使用一個不同的y
變量,而所有這些關閉共享相同x
。