虹長貫氣
這個字典不是你平常國文課會用的那個教育部字典喔,在程式語言中,字典這項資料型態可以做的事情,你可以把他想成是一個可以在其中定義很多變數的變數,以日常生活中舉例就例如你的身分證,上面會印有你的生日、名字、性別、身分證字號...等,那依照上述情境,在Lua語言中會長這樣:
local MyInformationDetail = {
Name = "Grosstofu",
Gender = "Male",
IDCode = "F9487"
}
可以發現,字典的定義方式跟陣列很像,但不同於陣列,字典會將變數在{}裡定義好,而且在字典中,各項變數並沒有順序之分 (像陣列就可以把變數插入到陣列的某一項,但字典不會這麼定義),而要提取字典裡面的變數,就跟我們平常定義路徑的方法相同:
local MyInformationDetail = {
Name = "Grosstofu",
Gender = "Male",
IDCode = "F9487"
}
--現在,我想要輸出我的名字
print(MyInformationDetail.Name) --MyInformation 的 Name 的值
又或者,你也可以以變數的名稱來查找字典內的值
local MyInformationDetail = {
Name = "Grosstofu",
Gender = "Male",
IDCode = "F9487"
}
--用以下的方法也可以通
print(MyInformationDetail["Name"])
通常這項用法會是在你的變數名稱內有空格的時候,例如說我們現在在字典裡多加一項變數,叫做血型 Blood Type
local MyInformationDetail = {
Name = "Grosstofu",
Gender = "Male",
IDCode = "F9487"
["Blood Type"] = 'O' --只要前面加個中括號就可以以字串的形式為變數命名
}
但要記得,這個方法只可以在字典內使用,你不可以直接以 ["變數名稱"] 的方式為變數命名,因為變數名稱的第一個字元一定要是英文字母 A~Z 的大寫或小寫,其餘像是特殊符號 (!@#$%)、數字 (0~9)、中文字 (幹、屌)、注音 (ㄅ~ㄦ)等都不行。
至於要在後續新增物件到字典中,也不用像陣列一樣這麼麻煩 (不需要table.什麼什麼),你只需要用 字典名稱[變數名稱] = 變數的值 就可以了,像:
local MyInformationDetail = {
Name = "Grosstofu",
Gender = "Male",
IDCode = "F9487"
["Blood Type"] = 'O'
}
--現在,我想變性成女生
MyInformation.Gender = "Female"
--然後,我結婚了,所以我的身分證要多加一份配偶欄,且變數值為是
MyInformation["IsMarried"] = true
--所以這個時候就可以用print來看我結婚了沒
print(MyInformation["IsMarried"])
--或者可以用我們第一個教的方法,因為我是否有配偶的這個變數名稱內沒有空格
print(MyInformation.IsMarried)
接下來,我們要來看如何遍歷一項字典。
首先,我們來了解一下什麼是遍歷,所謂的遍歷就是提取出字典內的所有物件做同一件事,或者你也可以用我們之前講過的if then判斷式來過濾所提取的物件,有點難懂對吧,我們用一個情境來講解。
還記得我們在講迴圈的時候用過的買番茄的例子吧? 現在我們番茄已經全部買到了,接下來我們來把番茄全部放到字典裡分類,每顆番茄的屬性有: 大小 (大 中 小)、顏色 (紅、橘、綠)、是否壞掉 (是、否)
local Tomatoes = {
Tomato1 = { --想不到吧字典裡也可以放字典喔!
Size = "大",
Color = "橘",
IsRotten = false
}, --啊要記得放這個逗點
Tomato2 = {
Size = "小",
Color = "紅",
IsRotten = false
},
Tomato3 = {
Size = "中",
Color = "紅",
IsRotten = true
},
Tomato4 = {
Size = "大",
Color = "綠",
IsRotten = false
},
Tomato5 = {
Size = "小",
Color = "橘",
IsRotten = false
},
}
現在全部分類好了,接著你媽叫你先把壞掉的番茄挑出來,這時你一定會想到: 用if then判斷式把符合值的變數挑出來就可以了!
local Tomatoes = {} --這邊我就省略了嘿
if Tomatoes.Tomato1.IsRotten == true then
Tomatoes.Tomato1 = nil --把Tomato1的值變成沒東西,也就是把它刪掉的意思
end
--靠杯等一下好像有點太多了
欸嘿太多了對吧,那聰明的你肯定會想到第二個解決辦法,也就是使用for迴圈對吧!
local Tomatoes = {} --這邊我就省略了嘿
for i = 0, 5, 1 do
--等等,變數的名字都不一樣,而且他也沒有順序可以讓我一個一個看啊!!!
end
那總之恭喜你走入了一個死胡同,不過使用for迴圈的這個想法是正確的,但我們要用另一個方法來取得字典內的變數
local Tomatoes = {} --這邊我就省略了嘿
--好,既然不能這樣,那把變數名稱跟變數值提取出來總可以了吧
for index, value in pairs(Tomatoes) do
--好欸,現在index是變數的名稱,value就是變數的值了!
--所以我只要判斷這一次就可以了!
if value.IsRotten == true then
print(index)
index = nil
end
end
等等等等等,怎麼突然多了index還有value,然後這跟我們之前學的for迴圈完全不一樣啊!!
好好好先別激動,我先來講一個概念,我們在講迴圈的時候有提到,迴圈的第三個值是更新值,那這個更新值如果沒有特別定義的話,他的預設就會是1 (也就是初始值每次+1),也就是說,我們在上述的for迴圈省略了更新值,好這個解決了,但為什麼又突然跑出了index跟value這兩個數值呢?
index這個我們在迴圈那邊講過,但這邊我們卻沒有給予他一個數值,而value也沒有,這是為什麼呢? 其實是因為我們在後面用的 in pairs()這項函式所回傳的值會有兩個值,而這兩個值就是index跟value,那in這個好理解吧,就是在裡面的意思,而在什麼東西裡面呢,這個東西就是我們用pairs()函式所遍歷出來的值,pairs()這項函式可以把我們在參數內所給予的字典的所有值全部拿出來,並全部統整成前面的index與value部分,這也是為什麼我們在迴圈內只需要判斷一次就可以把所有的值全部判斷過。
但pairs與ipairs又有什麼不同呢,在平常使用時他們並沒有任何的不同,但如果在每一次迴圈都會等待一次的時候,這兩個函式就會有所差異了,我們來看以下的程式碼:
--我們先以pairs來舉例
for i, v in pairs(Tomatoes) do --欸對這兩個index還有value的值的名稱可以隨便改
task.wait(1)
print(i, v) --這個用法可以同時輸出兩個變數值
end
此時的輸出就會是
--等一秒
Tomato1, {Size = "大",Color = "橘",IsRotten = false}
--再等一秒
Tomato2, ......
而當我們使用的是ipairs,輸出就會像這樣:
--欸那個pairs跟ipairs的用法就差在他們的名稱所以程式我就不在寫一次了
--等一秒
Tomato1 = {
Size = "大",
Color = "橘",
IsRotten = false
},
Tomato2 = {
Size = "小",
Color = "紅",
IsRotten = false
},
Tomato3 = {
Size = "中",
Color = "紅",
IsRotten = true
},
Tomato4 = {
Size = "大",
Color = "綠",
IsRotten = false
},
Tomato5 = {
Size = "小",
Color = "橘",
IsRotten = false
}
看出差別了吧! pairs會在每一次的迴圈處理一個的字典內變數,但ipairs會在一次迴圈中處理所有的變數。
好那既然我們已經學會了遍歷的概念,我們也可以把它用在陣列裡
local array = {1, 2, 3, 4, 5}
for i = 1, 5 do
--因為陣列裡的值就是一個完整的值,所以沒有value,但還是有index可以用
array[i] *= 2
print(array[i])
end
要記得,Lua語言中的陣列的第一項的位置就是1,跟其他語言的第一項為0的概念不同,所以for迴圈的初始值必須是1,否則會報錯。
當然,也可以用if then判斷式來過濾所選的值
local array = {1, 2, 3, 4, 5}
for i = 1, 5 do
if array[i] > 3 then
array[i] *= 2
print(array[i])
end
end
這樣輸出的值就只剩下4跟5乘2的值了。
明天我們將會進入到真正有趣的單元了