> 1.0 翻譯:[siemenliu](https://github.com/siemenliu)?校對:[zq54zquan](https://github.com/zq54zquan)
>
> 2.0 翻譯+校對:[shanksyang](https://github.com/shanksyang)
本頁包含內容:
[TOC]
_下標腳本_?可以定義在類(Class)、結構體(structure)和枚舉(enumeration)這些目標中,可以認為是訪問集合(collection),列表(list)或序列(sequence的快捷方式,使用下標腳本的索引設置和獲取值,不需要再調用實例的特定的賦值和訪問方法。舉例來說,用下標腳本訪問一個數組(Array)實例中的元素可以這樣寫?`someArray[index]`?,訪問字典(Dictionary)實例中的元素可以這樣寫?`someDictionary[key]`。
對于同一個目標可以定義多個下標腳本,通過索引值類型的不同來進行重載,下標腳本不限于單個緯度,你可以定義多個入參的下標腳本滿足自定義類型的需求。
> 譯者:這里附屬腳本重載在本小節中原文并沒有任何演示
## 下標腳本語法
下標腳本允許你通過在實例后面的方括號中傳入一個或者多個的索引值來對實例進行訪問和賦值。語法類似于實例方法和計算型屬性的混合。與定義實例方法類似,定義下標腳本使用`subscript`關鍵字,顯式聲明入參(一個或多個)和返回類型。與實例方法不同的是下標腳本可以設定為讀寫或只讀。這種方式又有點像計算型屬性的getter和setter:
~~~
subscript(index: Int) -> Int {
get {
// 返回與入參匹配的Int類型的值
}
set(newValue) {
// 執行賦值操作
}
}
~~~
`newValue`的類型必須和下標腳本定義的返回類型相同。與計算型屬性相同的是set的入參聲明`newValue`就算不寫,在set代碼塊中依然可以使用默認的`newValue`這個變量來訪問新賦的值。
與只讀計算型屬性一樣,可以直接將原本應該寫在`get`代碼塊中的代碼寫在`subscript`中:
~~~
subscript(index: Int) -> Int {
// 返回與入參匹配的Int類型的值
}
~~~
下面代碼演示了一個在`TimesTable`結構體中使用只讀下標腳本的用法,該結構體用來展示傳入整數的_n_倍。
~~~
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
print("3的6倍是\(threeTimesTable[6])")
// 輸出 "3的6倍是18"
~~~
在上例中,通過`TimesTable`結構體創建了一個用來表示索引值三倍的實例。數值`3`作為結構體`構造函數`入參初始化實例成員`multiplier`。
你可以通過下標腳本來得到結果,比如`threeTimesTable[6]`。這條語句訪問了`threeTimesTable`的第六個元素,返回`6`的`3`倍即`18`。
> 注意:
> `TimesTable`例子是基于一個固定的數學公式。它并不適合對`threeTimesTable[someIndex]`進行賦值操作,這也是為什么附屬腳本只定義為只讀的原因。
## 下標腳本用法
根據使用場景不同下標腳本也具有不同的含義。通常下標腳本是用來訪問集合(collection),列表(list)或序列(sequence)中元素的快捷方式。你可以在你自己特定的類或結構體中自由的實現下標腳本來提供合適的功能。
例如,Swift 的字典(Dictionary)實現了通過下標腳本來對其實例中存放的值進行存取操作。在下標腳本中使用和字典索引相同類型的值,并且把一個字典值類型的值賦值給這個下標腳本來為字典設值:
~~~
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
numberOfLegs["bird"] = 2
~~~
上例定義一個名為`numberOfLegs`的變量并用一個字典字面量初始化出了包含三對鍵值的字典實例。`numberOfLegs`的字典存放值類型推斷為`[String:Int]`。字典實例創建完成之后通過下標腳本的方式將整型值`2`賦值到字典實例的索引為`bird`的位置中。
更多關于字典(Dictionary)下標腳本的信息請參考[讀取和修改字典](http://wiki.jikexueyuan.com/project/swift/chapter2/04_Collection_Types.html#accessing_and_modifying_a_dictionary)
> 注意:
> Swift 中字典的附屬腳本實現中,在`get`部分返回值是`Int?`,上例中的`numberOfLegs`字典通過附屬腳本返回的是一個`Int?`或者說“可選的int”,不是每個字典的索引都能得到一個整型值,對于沒有設過值的索引的訪問返回的結果就是`nil`;同樣想要從字典實例中刪除某個索引下的值也只需要給這個索引賦值為`nil`即可。
## 下標腳本選項
下標腳本允許任意數量的入參索引,并且每個入參類型也沒有限制。下標腳本的返回值也可以是任何類型。下標腳本可以使用變量參數和可變參數,但使用寫入讀出(in-out)參數或給參數設置默認值都是不允許的。
一個類或結構體可以根據自身需要提供多個下標腳本實現,在定義下標腳本時通過入參個類型進行區分,使用下標腳本時會自動匹配合適的下標腳本實現運行,這就是_下標腳本的重載_。
一個下標腳本入參是最常見的情況,但只要有合適的場景也可以定義多個下標腳本入參。如下例定義了一個`Matrix`結構體,將呈現一個`Double`類型的二維矩陣。`Matrix`結構體的下標腳本需要兩個整型參數:
~~~
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`,創建了一個足夠容納`rows * columns`個數的`Double`類型數組。通過傳入數組長度和初始值0.0到數組的一個構造器,將`Matrix`中每個元素初始值0.0。關于數組的構造方法和析構方法請參考[創建一個空數組](http://wiki.jikexueyuan.com/project/swift/chapter2/04_Collection_Types.html#creating_an_empty_array)。
你可以通過傳入合適的`row`和`column`的數量來構造一個新的`Matrix`實例:
~~~
var matrix = Matrix(rows: 2, columns: 2)
~~~
上例中創建了一個新的兩行兩列的`Matrix`實例。在閱讀順序從左上到右下的`Matrix`實例中的數組實例`grid`是矩陣二維數組的扁平化存儲:
~~~
// 示意圖
grid = [0.0, 0.0, 0.0, 0.0]
col0 col1
row0 [0.0, 0.0,
row1 0.0, 0.0]
~~~
將值賦給帶有`row`和`column`下標腳本的`matrix`實例表達式可以完成賦值操作,下標腳本入參使用逗號分割
~~~
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2
~~~
上面兩條語句分別`讓matrix`的右上值為 1.5,坐下值為 3.2:
~~~
[0.0, 1.5,
3.2, 0.0]
~~~
`Matrix`下標腳本的`getter`和`setter`中同時調用了下標腳本入參的`row`和`column`是否有效的判斷。為了方便進行斷言,`Matrix`包含了一個名為`indexIsValidForRow(_:column:)`的成員方法,用來確認入參的`row`或`column`值是否會造成數組越界:
~~~
func indexIsValidForRow(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
~~~
斷言在下標腳本越界時觸發:
~~~
let someValue = matrix[2, 2]
// 斷言將會觸發,因為 [2, 2] 已經超過了matrix的最大長度
~~~
- 介紹
- 歡迎使用 Swift
- 關于 Swift
- Swift 初見
- Swift 版本歷史記錄
- Swift1.0 發布內容
- Swift 教程
- 基礎部分
- 基本運算符
- 字符串和字符
- 集合類型
- 控制流
- 函數
- 閉包
- 枚舉
- 類和結構體
- 屬性
- 方法
- 下標腳本
- 繼承
- 構造過程
- 析構過程
- 自動引用計數
- 可選鏈
- 錯誤處理
- 類型轉換
- 嵌套類型
- 擴展
- 協議
- 泛型
- 權限控制
- 高級操作符
- 語言參考
- 關于語言參考
- 詞法結構
- 類型
- 表達式
- 語句
- 聲明
- 特性
- 模式
- 泛型參數
- 語法總結
- 蘋果官方Blog官方翻譯
- Access Control 權限控制的黑與白
- 造個類型不是夢-白話Swift類型創建
- WWDC里面的那個“大炮打氣球”
- Swift與C語言指針友好合作
- 引用類型和值類型的恩怨
- 訪問控制和Protected
- 可選類型完美解決占位問題