類,結構和枚舉類型都可以通過定義下標來訪問一組或者一個序列中的成員元素。通過下標索引就可以方便地檢索和設定相應的值,而不需要其他的額外操作。比如你可以通過someArray[index]來訪問數組中的元素,或者someDictionary[key]來對字典進行索引。
你可以為一個類型定義多個下標,以及適當的下標重載用來根據傳遞給下標的索引來設定相應的值。下標不僅可以定義為一維的,還可以根據需要定義為多維的,多個參數的。
1、下標文法
下標可以讓你通過執行個體名後加中括弧內一個或多個數值的形式檢索一個元素。文法和方法文法和屬性文法類似,通過使用subscript關鍵定義,一個或多個輸入參數以及一個傳回值。不同於執行個體方法的是,下標可以是可讀寫的或者唯讀。這種行為通過一個getter和setter語句聯通,就像是計算屬性一樣。
複製代碼 代碼如下:
subscript(index: Int) -> Int {
get {
// return an appropriate subscript value here
}
set(newValue) {
// perform a suitable setting action here
}
}
newValue的類型和下標返回的類型一樣。和計算屬性一樣,你可以選擇不指定setter的參數,因為當你不指定的時候,預設參數newValue會被提供給setter。
和計算屬性一樣,唯讀下標可以不需要get關鍵詞:
複製代碼 代碼如下:
subscript(index: Int) -> Int {
// return an appropriate subscript value here
}
下面是一個唯讀下標的實現,定義了一個TimesTable結構來表示一個整數的倍數表:
複製代碼 代碼如下:
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
println("six times three is \(threeTimesTable[6])")
// prints "six times three is 18"
在這個例子中,執行個體TimesTable被建立為3倍數表,這是通過在初始化的時候為multiplier參數傳入的數值3設定的。
注意:
倍數表是根據特定的數學規則設定的,所以不應該為threeTimeTable[someIndex]元素設定一個新值,所以TimesTable的下標定義為唯讀。
2、下標的使用
下標的具體含義由使用它時的上下文來確定。下標主要用來作為集合,列表和序列的元素捷徑。你可以自由的為你的類或者結構定義你所需要的下標。
比如說,Swift中字典類型實現的下標是設定和檢索字典執行個體中的值。可以通過分別給出下標中的關鍵詞和值來設定多個值,也可以通過下標來設定單個字典的值:
複製代碼 代碼如下:
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
numberOfLegs["bird"] = 2
上面的例子中定義了一個變數numberOfLegs,然後通過索引值對初始化。numberOfLegs的類型是字典類型Dictionary<String, Int>。在字典建立之後,例子使用了下標賦值方法添加了一個類型為字串的鍵”bird”和Int值2到字典中。
更多關於字典的下標可以參考:訪問和修改字典這一章節
注意:
Swift中字典類型實現的索引值對下標是可選類型。對於numberOfLges字典來說,返回的值是Int?,也就是可選Int值。字典的這種使用可選類型下標的方式說明不是所有的鍵都有對應的值。同樣也可以通過給鍵賦值nil來刪除這個鍵。
3、下標選項
下標可以接收任意數量的參數,參數的類型也可以各異。下標還可以返回任何類型的值。下標可以使用變數參數或者可變參數,但是不能夠使用輸入輸出參數或者提供預設參數的值。
類或者結構可以根據需要實現各種下標方式,可以在需要的時候使用合適的下標通過中括弧中的參數返回需要的值。這種多下標的定義被稱作下標重載。
當然,最常見的下標用法是單個參數,也可以定義多個參數的下標。下面的例子示範了一個矩陣Matrix結構,它含有二維的Double值。矩陣結構的下標包括兩個整形參數:
複製代碼 代碼如下:
struct Matrix {
let rows: Int, columns: Int
var grid: Double[]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(count: rows * columns, repeatedValue: 0.0)
}
func indexIsValidForRow(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
subscript(row: Int, column: Int) -> Double {
get {
assert(indexIsValidForRow(row, column: column), "Index out of range")
return grid[(row * columns) + column]
}
set {
assert(indexIsValidForRow(row, column: column), "Index out of range")
grid[(row * columns) + column] = newValue
}
}
}
矩陣Matrix提供了一個初始化方法,使用兩個參數rows和columns,然後建立了一個數組來儲存類型為Double的值rows*columns。每個矩陣中的位置都被設定了一個初始值0.0。通過傳遞初始值0.0和數組長度給數組初始化方法完成上述操作。數組的初始化方法在:建立和初始化數組中有更詳細的敘述。
你可以傳遞兩個參數row和column來完成Matrix的初始化:
複製代碼 代碼如下:
var matrix = Matrix(rows: 2, columns: 2)
上面的初始化操作建立了一個兩行兩列的矩陣Matrix執行個體。這個矩陣執行個體的grid數組看起來是平坦的,但是實際上是矩陣從左上到右下的一維儲存形式。
矩陣中的值可以通過使用包含row和column以及逗號的下標來設定:
複製代碼 代碼如下:
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2
這兩個語句調用了下標的setter方法為右上和左下角的兩個元素分別賦值1.5和3.2
矩陣下標的getter和setter方法都包括了一個Assert 陳述式來檢查下標row和column是否有效。通過indexIsValid方法來判斷row和column是否在矩陣的範圍內:
複製代碼 代碼如下:
func indexIsValidForRow(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
如果訪問的矩陣越界的時候,斷言就會被觸發:
複製代碼 代碼如下:
let someValue = matrix[2, 2]
// this triggers an assert, because [2, 2] is outside of the matrix bounds