【正文】
值,他的屬性和其他任何值都有區(qū)別;通常它代表沒有有效的值。(構(gòu)建Lua解釋器時也可以很容易地用其他內(nèi)部的表示方式表示數(shù)字,如單精度浮點數(shù)或者長整型)。) (見 )。 用戶數(shù)據(jù)類型(userdata) 提供了讓任意C數(shù)據(jù)儲存在Lua變量中的功能。 Userdata 值不能在Lua中建立或者修改,只能通過 C 表(table) 類型實現(xiàn)了聯(lián)合數(shù)組,也就是說,數(shù)組不僅可以使用數(shù)字,還能使用其他的值(除了 nil)。語言支持 這種比較優(yōu)美的表示方式,還有 a[name]。這樣表也可以支持 方法(methods) (見 )。 類型轉(zhuǎn)換Lua提供運(yùn)行時的數(shù)字和字符串值得自動轉(zhuǎn)換。 一個名稱可以表示全局變量或局部變量(或者一個函數(shù)的正式參數(shù),一種局部變量的特殊形式): var ::= NameLua假設(shè)變量是全局變量,除非明確地用local進(jìn)行聲明 (見 )。 exp `]180。 Name訪問全局變量和表字段的實質(zhì)可以通過元表進(jìn)行改變。我們在這里僅僅用來解釋原理)。當(dāng)新創(chuàng)建一個函數(shù)時,它會繼承創(chuàng)建它的函數(shù)的環(huán)境。我們這里僅僅用來解釋原理) 語句Lua支持一種很通俗的語句集,和Pascal或者C中的很相似。每一個語句后面都可以加上一個分號(可選): chunk ::= {stat [`。 一段語句可以儲存在文件內(nèi)或者宿主程序的一個字符串中。 語句塊一個語句塊是一系列語句;從語句構(gòu)成上來看,語句塊等同于語句段: block ::= chunk一個語句塊可以明確定界來替換單個語句: stat ::= do block end顯式語句塊可以很好地控制變量的聲明范圍。兩邊的表中的元素都用逗號分隔開來: stat ::= varlist1 `=180。 在賦值之前,值的表長度會被 調(diào)整 為和變量的表一樣。 賦值語句首先計算出所有的表達(dá)式,然后才會執(zhí)行賦值,所以代碼: i = 3 i, a[i] = i+1, 20設(shè)置 a[3] 為 20,但不影響 a[4]。對一個索引變量的賦值 t[i] = val 等同于 settable_event(t,i,val)。(_env 變量并未在Lua中定義。false 和 nil 都表示假。 stat ::= breakbreak 結(jié)束最里面的一個循環(huán)。這樣現(xiàn)在 return 和 break 就成為他們(內(nèi)部)語句塊中的最后一個語句了。語法如下: stat ::= for Name `=180。一個這樣的 for 語句: for var = 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 while (_step0 and var=_limit) or (_step=0 and var=_limit) do block var = var + _step end end注意: _limit 和 _step 是不可見的變量。 每一個迭代過程,它調(diào)用迭代函數(shù)來產(chǎn)生新的值,直到新的值是 nil 。他的結(jié)果是一個 迭代 函數(shù),一個 狀態(tài),和給第一個 迭代變量的一個初始值。 函數(shù)調(diào)用將在 詳細(xì)解釋。 Name}如果出現(xiàn)初始賦值,他的語法和多重賦值語句一樣(見 )。 局部變量的可見規(guī)則會在 。 一個用括號括起的表達(dá)式只會返回一個值。如果操作數(shù)是數(shù)字,或者是可以轉(zhuǎn)換成數(shù)字的字符串(見 ),那么所有的操作都和算術(shù)意義上的運(yùn)算一致(除了指數(shù))。 等于 (==) 先比較操作數(shù)的類型。每次你創(chuàng)建一個新的對象(表,用戶數(shù)據(jù),或者是函數(shù))。這樣, 0==0 結(jié)果是 false ,同樣 t[0] 和 t[0] 給出的是表中不同的字段。如果,兩個參數(shù)都是字符串,那么它們的值會根據(jù)當(dāng)前的區(qū)域設(shè)置進(jìn)行比較。 合取運(yùn)算 and 如果第一個參數(shù)是 false 或者 nil 則返回第一個參數(shù);否則 and 返回第二個參數(shù)。)。串聯(lián)接符 (`..180。 表構(gòu)造器表構(gòu)造器是創(chuàng)建表的表達(dá)式。 [fieldlist] `}180。 exp | Name `=180。[exp1] = exp2 形式的每一個添加到新表中的字段條目以 exp1 為鍵并以 exp2 為值。例如: a = {[f(1)] = g。如果要避免這種情況,在函數(shù)調(diào)用兩邊加上括號(見 )。否則,他的 call 元方法就會被調(diào)用,第一個參數(shù)是 prefixexp 的值,接下來是原來的調(diào)用參數(shù)(見 )。 參數(shù)可以有以下幾種語法: args ::= `(180。 f39。) 要好,是因為參數(shù)列表是一個單獨的字符串。 以下是一些例子: f() 調(diào)整為0個結(jié)果 g(f(), x) f() 被調(diào)整成1個結(jié)果 g(x, f()) g 獲得 x 加上f()返回的所有值 a,b,c = f(), x f() 被調(diào)整成1個結(jié)果(此時c獲得nil值) a,b,c = x, f() f() 被調(diào)整為兩個結(jié)果 a,b,c = f() f() 被調(diào)整為3個結(jié)果 return f() 返回所有 f() 返回的值 return x,y,f() 建立一個表包含所有 f() 返回的值 {f()} creates a list with all values returned by f() {f(), nil} f() 被調(diào)整為一個結(jié)果如果你用括號括起調(diào)用的函數(shù),那么它就會被調(diào)整為返回一個值。如果你寫: a = f (g).x(a)Lua會讀作 a = f(g).x(a)。Lua實現(xiàn)了proper tail calls;在一個尾部調(diào)用中,被調(diào)用的函數(shù)將會重新使用調(diào)用程序的棧。所以,下面的例子都不是尾部調(diào)用: return (f(x)) results adjusted to 1 return 2 * f(x) return x, f(x) additional results f(x)。 Name} [`:180。這樣,當(dāng)Lua執(zhí)行函數(shù)定義的時候,函數(shù)被 實例化 (封裝 closed)。 parlist1 ::= namelist [`,180。變長參數(shù)函數(shù)在其參數(shù)列表最后有三個點 (`...180。`n180。n是額外的參數(shù)。如果控制到達(dá)了函數(shù)尾部而沒有遇到 return 語句,那么函數(shù)沒有返回值。例如: x = 10 global variable do new block local x = x new `x39。例如: local counter = 0 function inc (x) counter = counter + x return counter end內(nèi)部函數(shù)使?玫木植勘淞吭諍誆砍浦? 上值(upvalue),或者 外局部變量(external local variable)。每個閉包使用不同的 y 變量,但他們共享同一個 x 變量。如果你要在Lua中捕獲錯誤,你可以使用 pcall 函數(shù)(見 )。例如,當(dāng)一個對象是一個加法的操作數(shù)時,Lua檢查它的元表中的 __add 字段是不是一個函數(shù)。 你可以通過 set/getmetatable 函數(shù)來查詢和更改一個對象的元表(見 )。當(dāng)Lua對一個表或是一個用戶數(shù)據(jù)執(zhí)行上面中的一個操作時,它先檢查元表控制的操作已經(jīng)羅列在下面。描述中用到的函數(shù) (rawget, tonumber, 等等) 在 中會對他們進(jìn)行描述。 下面的 getbinhandler 函數(shù)定義了Lua如何給一個二元操作選擇一個處理器。 here is the primitive `add39。 div: / 操作。 function pow_event (op1, op2) call the handler with both operands end return o `39。 Try to get a handler from the operand return h(op, nil) end function concat_event (op1, op2) else else end local mm2 = metatable(op2)[event] elseif type(op1) == string and type(op2) == string then if h thena b is equivalent to b a. if type(op1) == number and type(op2) == number then else else else end local v = rawget(table, key) else return h(table, key) call the handler local v = rawget(table, key) if h == nil then rawset(table, key, value)。 if h == nil then end end function function_event (func, ...) local h = metatable(func).__call error(...)這意味著你不需要擔(dān)心新對象的內(nèi)存分配問題,也不需要釋放不用的對象。一個數(shù)字表示Lua使用的動態(tài)內(nèi)存的字節(jié)數(shù),另一個是閥值。將閥值設(shè)為零時會強(qiáng)制立刻進(jìn)行垃圾收集,同時把他設(shè)為足夠大就可以停止垃圾收集。這些元方法也稱為 終結(jié)器(finalizers)。收集完畢之后,Lua會對這個列表中的用戶數(shù)據(jù)執(zhí)行和以下函數(shù)相等的操作: function gc_event (udata) local h = metatable(udata).__gc if h then h(udata) end end在每個垃圾收集過程最后,調(diào)用用戶數(shù)據(jù)的終結(jié)器的順序,將按照他們在收集過程中添加到列表中的相反順序進(jìn)行。換句話說,如果指向一個對象的引用只有弱引用,那么這個對象還是要被垃圾收集器回收。無論哪種情況,只要鍵或者值中的一個被回收了,那么這一對鍵值將會從表中刪除。的字符串,那么表中的鍵是弱鍵。否則,這個元表控制的表的弱表行為將會不確定。 你可以調(diào)用 來創(chuàng)建一個同步程序。傳給 的額外的參數(shù)會作為同步程序主函數(shù)的參數(shù)傳遞過去。在有錯誤的情況下, 返回 false ,并附上錯誤信息。的所有參數(shù)。函數(shù)將返回resume返回的所有值,出除了第一個(布爾值的錯誤代碼)。所有這些宏(macro)都只使用一次它的參數(shù)(除了第一個參數(shù)、這個每次總是一個Lua狀態(tài)),所以不會產(chǎn)生隱藏的副作用。該函數(shù)從最開始創(chuàng)建一個Lua狀態(tài)。在個別的平臺上,?慊蛐聿恍枰饔謎飧齪蛭彼拗鞒絳蚪崾氖焙蚧嶙勻壞氖頭潘械淖試礎(chǔ)A硪環(huán)矯媯な奔湓誦械某絳潁褚恍┦鼗そ袒蛘遅eb服務(wù)器,可能需要立即釋放那些不需要的狀態(tài)資源,以避免占用太多內(nèi)存。這個棧最初包含了C函數(shù)的所有參數(shù),并且這也會存放C函數(shù)的返回值(見 )。我們說一個索引存在于 1 和棧頂之間是有效的,換句話說,如果 1 = abs(index) = top。這個函數(shù) int lua_checkstack (lua_State *L, int extra)。LUA_MINSTACK 定義在 中,它的值是 20,所以你不需要總擔(dān)心??臻g除非你的代碼通過循環(huán)將元素壓入棧。amp。 除非另外說明,任何函數(shù)接受有效索引可以被稱為是 偽索引(pseudoindices),這些索引代表一些Lua值可以被C 代碼訪問但是卻不存在于棧中。 void lua_remove (lua_State *L, int index)。如果新的棧頂比舊的更大,那么新元素被填上 nil 值。 lua_remove 刪除指定位置的元素,將該元素上方的所有元素下移以填滿空缺。(你不能使用偽索引調(diào)用 lua_remove 或 lua_insert,因為他們不代表棧中的位置。 int lua_isboolean (lua_State *L, int index)。 int lua_isfunction (lua_State *L, int index