在基礎篇的開頭有介紹,Swift 有三個主要的 Collection Types:Array、Set 以及 Dictionary,其中只有 Array 是有順序地排列,其他兩個則不是,而且這三個型都是泛型集合 ( Generic Collection ),所以可以指派任何型別的值,今天首部曲就來介紹 Array。
Array 是一個有順序排列的集合資料,你可以用透過 Array<Element>
來註記型別,你也可以使用 [Element]
,然而 Element 必須輸入一個型別:
var 購物清單1: Array<String> = []
var 購物請單2: [String] = []
或是直接使用 [Element]()
作為初始值,這三個的功能都是一樣的喔!
var 購物清單3 = [String]()
print(購物清單1 == 購物清單2) // True
print(購物清單2 == 購物清單3) // True
這邊使用的是一個 String 陣列,只要在中括號裡的每個 String 之間加上 ,
,即可指派到購物清單作為初始值。
var 購物清單: [String] = ["陶朱隱園", "藍寶堅尼", "LEGO 75978"]
但是你不能將非 String 的資料放在 String 陣列裡,假使我們在購物清單中加入整數 100,這時候就會跳出 Cannot convert value of type 'Int' to expected element type 'String'
錯誤,Xcode 溫馨小提醒你不能將整數型別的數值放入一個 String 陣列中。
還記得型別推斷嗎?你也可以不用特別註記型別,直接指派初始值,在編譯的時候透過型別推斷,就可以知道型別,在 Array 也是如此喔。
var 購物清單 = ["陶朱隱園", "藍寶堅尼", "LEGO 75978"] // 這是一個 [String] 變數
var 每日溫度表 = [37.1, 35.3, 36.3, 37.2, 32.7] // 這是一個 [Double] 變數
老師,這裏有一個疑問 ><:
如果在沒型別註記的 array 裡,加了一個有著不同型別的值,這時候型別推斷的結果為何?
問得很好 ( 自問自答 ),我們來看下面這個範例:
var anyArray = ["abc", 123, 456.789, true]
如果你在 Playground 上,他會跳出一個錯誤跟你說 Heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional
,簡單來說就是他不太確定這個變數到底是什麼,所以這邊就推斷為 Any,你如果真的要使用的話必須在後面加上 as [Any]
。
Any 可以代表著任何型別,所以在編譯的時候發現該陣列中有著不同型別的數值,就會自動推斷為 [Any]
型別,但這種宣告方式只推薦用於「你很清楚知道這個變數要做什麼」,否則很容易因為型別錯誤早成程式碼中斷,在後面的文章會再來細部探討 Any Type。
到這裡幾乎都是以 [String]
型別作為範例,你也可以試試看其他型別,像是 [Int]
、[Double]
、[Bool]
... 等
根據前面基礎的教學中可以知道,可以修改的前提就是宣告的必須是變數,我們就繼續以上面購物清單為範例,假定今天我們想修改 Array 中的值,有幾個方式
+
、+=
:還記得上一章基本運算子提到的,可以使用 +=
來達到相同的效果喔。Array.append(element)
var 購物清單 = [String]()
購物清單 = 購物清單 + ["藍寶堅尼"]
// ["藍寶堅尼"]
購物清單.append("LEGO 75978")
// ["藍寶堅尼", "LEGO 75978"]
但是這兩個方式也只能加在 Array 最尾端,但你有一種方式可以讓你加入到 Array 的任意位置中:Array.insert(value, at:)
。
購物清單.insert("陶朱隱園", at: 1)
// ["藍寶堅尼", "陶朱隱園", "LEGO 75978"]
「既然可以加,那一定可以移除囉!」
「沒錯,確實可以喔 ><」
「那上面使用 +=
來新增,移除是不是可以使用 -=
啊?」
「那可不行!」
移除你可以使用最粗暴的移除方法就是直接指派一個新的 Array,但是還是有其他的方式:
Array.remove(at:)
:移除某個特定位置的資料Array.removeFirst()
:移除陣列第一筆資料Array.removeLast()
:移除陣列最後一筆資料,效果跟 Array.popLast()
一樣購物清單.remove(at: 1)
// ["藍寶堅尼", "LEGO 75978"]
購物清單.removeFirst()
// ["LEGO 75978"]
購物清單.removeLast()
// []
如果你是想直接清空整個陣列,可以直接使用指派空陣列的方式,或是 Swift 提供了一個實體方法 Array.removeAll()
,可以用來清空整個陣列喔。
Array.removeLast()
跟 Array.popLast()
還是有點差別喔!可以看到官方 API 描述這兩個 method, removeLast() 以及 popLast(),他們的差異就在於如果要被處理的 Array 是空陣列的話,popLast() 會回傳 nil;removeLast() 則不允許這樣操作,會跳出一個 Fatal Error。
在上述的說明中只提到要如何新增及修改,但是要怎麼取用呢?
很簡單,只需要使用 Array[index]
的方式就可以取得你想要的值囉,來看下面範例:
var 購物清單 = ["藍寶堅尼", "陶朱隱園", "LEGO 75978", "口罩"]
print(購物清單[0]) // "藍寶堅尼"
print(購物清單[1]) // "陶朱隱園"
print(購物清單[2]) // "LEGO 75978"
print(購物清單[3]) // "口罩"
在 Swift 陣列裡的第一個元素的 index 的為 0,以此類推,所以你就可以針對你想索取的元素,輸入其 index 就可以找到囉,是不是很簡單!
但使用的時候要小心,假定今天我們輸入的 index 值超過了 Array 的大小的話,這時候就會跳出 Fatal error: Index out of range
的錯誤訊息。
print(購物清單[4]) // Fatal error: Index out of range
還記得在字串與字元那篇有提到一個協定 Collection
,同樣的 Array 也是實作了 Collection Protocol,所以你也可以使用 for ... in loop
,來走訪陣列裡每個元素。
for 購物項目 in 購物清單 {
print(購物項目)
}
/*
Prints:
藍寶堅尼
陶朱隱園
LEGO 75978
口罩
*/
除了照上述的這個方式走訪之外,也可以用簡單的回圈方式來實作,但是我們總得知道陣列的長度才能去界定範圍吧?
可以從 Array API 發現有一個 count 的屬性,我們可以用 count 來取得陣列的長度。
var 購物清單 = ["藍寶堅尼", "陶朱隱園", "LEGO 75978", "口罩"]
print("要買的東西總共有 \(購物清單.count) 項")
// 要買的東西總共有 4 項
所以我們也可以這麼做,也可以達到走訪的效果喔~
for i in 0..<購物清單.count {
print(購物清單[i])
}
/*
Prints:
藍寶堅尼
陶朱隱園
LEGO 75978
口罩
*/
再來介紹幾個檢查 Array 狀態的屬性及方法~
使用 Array.isEmpty
來檢查陣列是否為空陣列。
let emptyArray: Array<String> = []
let nonEmptyArray = ["1"]
print(emptyArray.isEmpty) // true
print(nonEmptyArray.isEmpty) // false
使用 Array.contains(element)
來檢查值是否存在於陣列中,這邊的 element 型別必須與 Array 的中的值型別相同,否則會跳出 error: cannot convert value ...
。
let intArray = [1, 3, 5, 7, 9]
print(intArray.contains(7)) // true
print(intArray.contains(2)) // false
print(intArray.contains("1")) // error: cannot convert value of type 'String' to expected argument type 'Int'