第4章
使用表
4.1
用表來儲存資料在Lua中,表是用來儲存其他變數(通常這些變數都是相互關聯的)的實體。它是成對元素的一個集合,每一對元素都由一個關鍵字和一個值組成,在表中,我們可以使用這個關鍵字來獲得與它唯一對應的值。
4.1.1
建立和索引表下面的代碼建立了一個表:> alice={}在Lua中,運算式{}可以建立一個表,這裡建立的是一個空表。alice是這個表的名稱,我們可以用如下的語句為這個表賦值:> alice["name"]="艾麗斯"> alice["phone"]="13883838438"> alice["address"]="三八胡同38號"> alice["city"]="暴風城"> alice["state"]="FS"這裡的每一行都在告訴Lua,可以通過中括弧裡的關鍵詞來獲得某個值:> print(alice["name"])艾麗斯> print(alice["address"])三八胡同38號中括弧裡的關鍵字可以是除nil之外的任一字元(默然說話:經測試,可以使用中文字元,不過,由於Lua的編譯器似乎對中文字元的支援不是太好,還是盡量避免使用吧)。這樣一來,我們也可以使用數字來作為關鍵字:> alice[1]="測試資料"> alice[2]=12> print(alice[1])測試資料> print(alice[2])12
4.1.2
從表中清除元素如果你使用一個在表中不存在的關鍵字時,表將返回一個nil。看例子:> print(alice["fax"])nil所以我們可以利用這一點,來完成對於值的清除:只要簡單的賦值為nil就可以了。> alice[1]=nil> alice[2]=nil> print(alice[1])nil
4.1.3
字串關鍵字的捷徑如果你的關鍵字是一個字串而不是一個數字,Lua提供了一種更加簡單的方法來使用它,例如,原來是這樣寫的:> alice["name"]="艾麗斯"現在你也可以這樣寫:> alice.name="艾麗斯"同樣,你也可以使用點的形式來訪問表中的值:> print(alice.name)艾麗斯> print(alice.address)三八胡同38號不過相對於沒有任何命名要求的中括弧的形式來說,點的這種形式對關鍵字的命名是有要求,它們必須以字母或底線開頭,並且整個關鍵字只能包括字母、數字和底線。中文字元,Lua的保留關鍵字符(如for,do,end等)都不能使用。所以alice[“姓名”]是正確的,但alice.姓名卻是不正確的。
4.1.4
建立有內容的表上面介紹的建立無內容的表,然後再給它鍵-值對的方式在實際使用中顯示有些羅嗦,下面這種形式大家一定會更喜歡:> alice={>> ["name"]="艾麗斯",>> ["address"]="三八胡同38號",>> ["state"]="FS",>> }類似於前面講的點引用方式,上面的代碼還可以更簡單(默然說話:當然,命名也就有要求了!)> alice={>> name="艾麗斯",>> address="三八胡同38號",>> state="FS",>> }大家要注意兩種寫法在文法格式上的相同點和不同點。相同點就是在每一個鍵—值對之間都有一個逗號分隔,最後一個鍵—值對的逗號可以打,也可以不打(默然說話:不過最好是打上,方便將來添加新的鍵--值對),不同之處就是一個要打中括弧和雙引號,另一個不用打中括弧和雙引號。
4.2
把表當作數組使用其實如果您學習過其他程式設計語言,在前面應該就有感覺。當Lua中的表使用了數字作為關鍵字時,它就和其他許多程式設計語言中的數組是很相似的。Lua把使用從1開始的連續整數作為關鍵字的表就稱為數組。
4.2.1
建立數組你可以這樣建立一個數組:array1={ 值1, 值2, 值3, ……}也可以這樣建立一個數組:array1={ [1]=值1, [2]=值2, [3]=值3, ……}所以我們說,數組是表的一種特殊形式。
4.2.2
擷取數組的長度第2章介紹過一個擷取字串長度的標識符(#),這個符號對於數組同樣適用:> tbl={"a","b","c"}> print(#tbl)3這個長度的最大用處就是在於遍曆時能夠提供一個動態下標:> for i=1,#tbl do>> print(tbl[i])>> endabc默然說話:這裡對#的使用是有限制的,也就是說,這個偽裝成數組的表,它的下標必須是從1開始的,而且必須是連續的。這樣,#得到的長度才是可靠的。
4.2.3
在數組中添加元素向數組中添加元素可以這樣很簡單的寫成:> tbl[#tbl+1]="a"但這樣的代碼很難讀懂,所以Lua提供了一個標準的table.insert()函數,可以讓添加數組元素變得簡單易懂。table.insert()的文法是:table.insert(數組,[下標,]值)參數的意義如下:l 數組——將被增加元素的數組l 下標——增加的元素所在的位置l 值——這個元素的值第二個參數打了中括弧,意思表明這個參數是可以省略的,如果你省略了它,這個值就會被添加到數組的末尾。我們還是具體用一個樣本來說明一下,首先我們作點準備工作,聲明一個數組,包括三個預設的字串:> tmp={"蘋果","香蕉","梨"}由於後面我們要反覆顯示這個數組裡的所有內容,所以我們再定義一個函數,它用於顯示一個數組中的全部內容:> print_tmp=function()>> for i=1,#tmp do>> print(i,tmp[i])>> end>> end先顯示一下當前內容:> print_tmp()1 蘋果2 香蕉3 梨之後,我們調用table.insert(),為這個數組再添加兩個水果試試。> table.insert(tmp,"芒果")> table.insert(tmp,"桔子")> print_tmp()1 蘋果2 香蕉3 梨4 芒果5 桔子大家看到,我們使用了省略第二個參數的形式,所以,新加入的兩個水果被在放了末尾,我們再來試試有三個參數的形式:> table.insert(tmp,3,"無花果")> print_tmp()1 蘋果2 香蕉3 無花果4 梨5 芒果6 桔子大家看到,無花果出現在了3的位置上,其他的水果都依次被移動了位置,並重新進行了編號。
4.2.4
從數組中刪除元素Lua提供了一個與table.insert()類似的函數table.remove()來執行刪除元素的操作,它的文法如下:值=table.remove(數組[,下標])這個函數有兩個參數l 數組——將被刪除元素的數組l 下標——被刪除元素所在的位置同樣,這個下標也是可以省略的,如果省略了,表示刪除數組中最後一個元素這個函數還有一個傳回值,它就是那個被刪除的元素值。來試試,接上面的例子,我們首先使用一個參數的形式:> table.remove(tmp)> print_tmp()1 蘋果2 香蕉3 無花果f4 梨5 芒果我們看到最後一個元素桔子被刪除了。接下來,再試試兩個參數的形式:> table.remove(tmp,3)> print_tmp()1 蘋果2 香蕉3 梨4 芒果大家可以看到,無花果被刪除了,但數組也及時進行了調整,它們的位置被重新進行了編號。
4.2.5
對數組中的元素排序如果數組的元素包括的是可以進行比較的元素時,有一個標準的庫函數table.sort()可以對它們進行排序。它的文法是:table.sort(數組[, 定序])table.sort()的第二個參數我們將在第5章詳細介紹,而第一個參數就是您需要排序的數組。我們還是來看個例子吧。由於前面的數組我們使用了漢字,而Lua對漢字的排序不是按我們的理解來進行的(默然說話:平常我們都是根據漢語拼音的英文排序或者是筆畫數的多少進行排序的,但Lua並未採用這兩種方式,它似乎只是簡單比較了漢字的編碼大小。這就讓我們很難理解了),所以我們重新聲明一個數組,並亂序初始化幾個英文字元:> tmp={"b","c","a","e","d"}先來列印一下:> print_tmp()1 b2 c3 a4 e5 d大家看到,是沒有排序的。現在,來排序一下,然後再列印:> table.sort(tmp)> print_tmp()1 a2 b3 c4 d5 e數組中的英文字元已經按字母順序進行了排序,整個數組裡,所有元素的位置順序也被進行了調整。
4.3
用名稱空間使用表前面介紹了幾個對數組進行處理的函數:l table.insert()l table.remove()l table.sort()從這一組函數的名稱上我們可以看出一個規律:它們都是以table.開頭的,這個table在這裡我們就稱它為名稱空間。名稱空間提供了一種對於相關函數的管理方式,它增加了我們對大量函數的管理能力。在Lua中,這種名稱空間其實就是一個表,所以上面的函數我們也可以使下面的形式進行調用:l table[“insert”]()l table[“remove”]()l table[“sort”]()下面我們就來學習如何建立名稱空間,換句話說,如何建立我們自己的函數庫。
4.3.1
建立util名稱空間建立一個名稱空間和建立一個表沒什麼區別:> util={}
4.3.2
向util中添加函數向名稱空間添加函數有兩種方法,如果你的函數已經定義好了,你可以直接將函數與一個鍵關聯起來。如果你的函數還沒有定義好,那你可以直接將函數定義賦值給一個鍵,下面舉例說明:
1.
儲存已有的函數還記得我們前面寫的溫度轉換函式嗎?如果你關閉過Lua編譯器,那麼把它再重新寫一遍:> convert_c2f=function(celsius)>> return (celsius*1.8)+32>> end好了,這個函數現在已經存在於Lua編譯器中了,接下來,我們把它賦值給util名稱空間:> util.c2f=convert_c2f現在,我們就可以使用util.c2f()的形式調用這個函數了,和你直接使用函數名convert_c2f是一樣的效果:> print(util.c2f(0))32
2.
定義新函數其實你完全可以不用去繞個彎子,你可以直接將函數的定義賦值給一個名稱空間的。下面是我們前面寫過的階乘函數,我們直接賦值給了util名稱空間:> util.factorial=function(num)>> local total=1>> for i=1,num do>> total=total*i>> end>> return total>> end上面的這種寫法,是我們在建立自己的函數庫時最常用的寫法。它的調用方式如下:> print(util.factorial(5))120