2.0 翻譯+校對:shanks
2.2 校對:SketchK 2016-05-13 3.0.1,shanks,2016-11-13
4.0 校對:kemchenj 2017-09-21
4.1 翻譯+校對:mylittleswift
本頁包含內(nèi)容:
下標可以定義在類、結(jié)構(gòu)體和枚舉中,是訪問集合、列表或序列中元素的快捷方式??梢允褂孟聵说乃饕?,設置和獲取值,而不需要再調(diào)用對應的存取方法。舉例來說,用下標訪問一個 Array 實例中的元素可以寫作 someArray[index],訪問 Dictionary 實例中的元素可以寫作 someDictionary[key]。
一個類型可以定義多個下標,通過不同索引類型進行重載。下標不限于一維,你可以定義具有多個入?yún)⒌南聵藵M足自定義類型的需求。
下標允許你通過在實例名稱后面的方括號中傳入一個或者多個索引值來對實例進行存取。語法類似于實例方法語法和計算型屬性語法的混合。與定義實例方法類似,定義下標使用 subscript 關鍵字,指定一個或多個輸入?yún)?shù)和返回類型;與實例方法不同的是,下標可以設定為讀寫或只讀。這種行為由 getter 和 setter 實現(xiàn),有點類似計算型屬性:
subscript(index: Int) -> Int {
get {
// 返回一個適當?shù)?Int 類型的值
}
set(newValue) {
// 執(zhí)行適當?shù)馁x值操作
}
}
newValue 的類型和下標的返回類型相同。如同計算型屬性,可以不指定 setter 的參數(shù)(newValue)。如果不指定參數(shù),setter 會提供一個名為 newValue 的默認參數(shù)。
如同只讀計算型屬性,可以省略只讀下標的 get 關鍵字:
subscript(index: Int) -> Int {
// 返回一個適當?shù)?Int 類型的值
}
下面代碼演示了只讀下標的實現(xiàn),這里定義了一個 TimesTable 結(jié)構(gòu)體,用來表示傳入整數(shù)的乘法表:
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
print("six times three is \(threeTimesTable[6])")
// 打印 "six times three is 18"
在上例中,創(chuàng)建了一個 TimesTable 實例,用來表示整數(shù) 3 的乘法表。數(shù)值 3 被傳遞給結(jié)構(gòu)體的構(gòu)造函數(shù),作為實例成員 multiplier 的值。
你可以通過下標訪問 threeTimesTable 實例,例如上面演示的 threeTimesTable[6]。這條語句查詢了 3 的乘法表中的第六個元素,返回 3 的 6 倍即 18。
注意
TimesTable例子基于一個固定的數(shù)學公式,對threeTimesTable[someIndex]進行賦值操作并不合適,因此下標定義為只讀的。
下標的確切含義取決于使用場景。下標通常作為訪問集合,列表或序列中元素的快捷方式。你可以針對自己特定的類或結(jié)構(gòu)體的功能來自由地以最恰當?shù)姆绞綄崿F(xiàn)下標。
例如,Swift 的 Dictionary 類型實現(xiàn)下標用于對其實例中儲存的值進行存取操作。為字典設值時,在下標中使用和字典的鍵類型相同的鍵,并把一個和字典的值類型相同的值賦給這個下標:
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
numberOfLegs["bird"] = 2
上例定義一個名為 numberOfLegs 的變量,并用一個包含三對鍵值的字典字面量初始化它。numberOfLegs 字典的類型被推斷為 [String: Int]。字典創(chuàng)建完成后,該例子通過下標將 String 類型的鍵 bird 和 Int 類型的值 2 添加到字典中。
更多關于 Dictionary 下標的信息請參考讀取和修改字典
注意
Swift 的
Dictionary類型的下標接受并返回可選類型的值。上例中的numberOfLegs字典通過下標返回的是一個Int?或者說“可選的 int”。Dictionary類型之所以如此實現(xiàn)下標,是因為不是每個鍵都有個對應的值,同時這也提供了一種通過鍵刪除對應值的方式,只需將鍵對應的值賦值為nil即可。
下標可以接受任意數(shù)量的入?yún)?,并且這些入?yún)⒖梢允侨我忸愋?。下標的返回值也可以是任意類型。下標可以使用變量參?shù)和可變參數(shù),但不能使用輸入輸出參數(shù),也不能給參數(shù)設置默認值。
一個類或結(jié)構(gòu)體可以根據(jù)自身需要提供多個下標實現(xiàn),使用下標時將通過入?yún)⒌臄?shù)量和類型進行區(qū)分,自動匹配合適的下標,這就是下標的重載。
雖然接受單一入?yún)⒌南聵耸亲畛R姷?,但也可以根?jù)情況定義接受多個入?yún)⒌南聵?。例如下例定義了一個 Matrix 結(jié)構(gòu)體,用于表示一個 Double 類型的二維矩陣。Matrix 結(jié)構(gòu)體的下標接受兩個整型參數(shù):
struct Matrix {
let rows: Int, columns: Int
var grid: [Double]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(repeating: 0.0, count: rows * columns)
}
func indexIsValid(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
subscript(row: Int, column: Int) -> Double {
get {
assert(indexIsValid(row: row, column: column), "Index out of range")
return grid[(row * columns) + column]
}
set {
assert(indexIsValid(row: row, column: column), "Index out of range")
grid[(row * columns) + column] = newValue
}
}
}
Matrix 提供了一個接受兩個入?yún)⒌臉?gòu)造方法,入?yún)⒎謩e是 rows 和 columns,創(chuàng)建了一個足夠容納 rows * columns 個 Double 類型的值的數(shù)組。通過傳入數(shù)組長度和初始值 0.0 到數(shù)組的構(gòu)造器,將矩陣中每個位置的值初始化為 0.0。關于數(shù)組的這種構(gòu)造方法請參考創(chuàng)建一個帶有默認值的數(shù)組。
你可以通過傳入合適的 row 和 column 的數(shù)量來構(gòu)造一個新的 Matrix 實例:
var matrix = Matrix(rows: 2, columns: 2)
上例中創(chuàng)建了一個 Matrix 實例來表示兩行兩列的矩陣。該 Matrix 實例的 grid 數(shù)組按照從左上到右下的閱讀順序?qū)⒕仃嚤馄交鎯Γ?/p>

將 row 和 column 的值傳入下標來為矩陣設值,下標的入?yún)⑹褂枚禾柗指簦?/p>
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2
上面兩條語句分別調(diào)用下標的 setter 將矩陣右上角位置(即 row 為 0、column 為 1 的位置)的值設置為 1.5,將矩陣左下角位置(即 row 為 1、column 為 0 的位置)的值設置為 3.2:

Matrix 下標的 getter 和 setter 中都含有斷言,用來檢查下標入?yún)?row 和 column 的值是否有效。為了方便進行斷言,Matrix 包含了一個名為 indexIsValid(row:column:) 的便利方法,用來檢查入?yún)?row 和 column 的值是否在矩陣范圍內(nèi):
func indexIsValid(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
斷言在下標越界時觸發(fā):
let someValue = matrix[2, 2]
// 斷言將會觸發(fā),因為 [2, 2] 已經(jīng)超過了 matrix 的范圍