鍍金池/ 教程/ iOS/ 下標(biāo)腳本(Subscripts)
方法 - Methods
關(guān)于 Swift
下標(biāo)腳本(Subscripts)
類和結(jié)構(gòu)體
類型轉(zhuǎn)換(Type Casting)
控制流
析構(gòu)過程(Deinitialization)
集合類型 (Collection Types)
構(gòu)造過程(Initialization)
Optional Chaining
枚舉(Enumerations)
自動引用計數(shù)
繼承(Inheritance)
擴展(Extensions)
泛型
字符串和字符(Strings and Characters)
函數(shù)(Functions)
高級運算符
訪問控制
基本運算符
嵌套類型
閉包(Closures)
協(xié)議
屬性 (Properties)

下標(biāo)腳本(Subscripts)

下標(biāo)腳本 可以定義在類(Class)、結(jié)構(gòu)體(structure)和枚舉(enumeration)這些目標(biāo)中,可以認(rèn)為是訪問對象、集合或序列的快捷方式,不需要再調(diào)用實例的特定的賦值和訪問方法。舉例來說,用下標(biāo)腳本訪問一個數(shù)組(Array)實例中的元素可以這樣寫 someArray[index] ,訪問字典(Dictionary)實例中的元素可以這樣寫 someDictionary[key]。

對于同一個目標(biāo)可以定義多個下標(biāo)腳本,通過索引值類型的不同來進行重載,而且索引值的個數(shù)可以是多個。

譯者:這里附屬腳本重載在本小節(jié)中原文并沒有任何演示

下標(biāo)腳本語法

下標(biāo)腳本允許你通過在實例后面的方括號中傳入一個或者多個的索引值來對實例進行訪問和賦值。語法類似于實例方法和計算型屬性的混合。與定義實例方法類似,定義下標(biāo)腳本使用subscript關(guān)鍵字,顯式聲明入?yún)ⅲㄒ粋€或多個)和返回類型。與實例方法不同的是下標(biāo)腳本可以設(shè)定為讀寫或只讀。這種方式又有點像計算型屬性的getter和setter:

    subscript(index: Int) -> Int {
        get {
            // 返回與入?yún)⑵ヅ涞腎nt類型的值
        }
        set(newValue) {
            // 執(zhí)行賦值操作
        }
    }

newValue的類型必須和下標(biāo)腳本定義的返回類型相同。與計算型屬性相同的是set的入?yún)⒙暶?code>newValue就算不寫,在set代碼塊中依然可以使用默認(rèn)的newValue這個變量來訪問新賦的值。

與只讀計算型屬性一樣,可以直接將原本應(yīng)該寫在get代碼塊中的代碼寫在subscript中:

    subscript(index: Int) -> Int {
        // 返回與入?yún)⑵ヅ涞腎nt類型的值
    }

下面代碼演示了一個在TimesTable結(jié)構(gòu)體中使用只讀下標(biāo)腳本的用法,該結(jié)構(gòu)體用來展示傳入整數(shù)的n倍。

    struct TimesTable {
        let multiplier: Int
        subscript(index: Int) -> Int {
            return multiplier * index
        }
    }
    let threeTimesTable = TimesTable(multiplier: 3)
    println("3的6倍是\(threeTimesTable[6])")
    // 輸出 "3的6倍是18"

在上例中,通過TimesTable結(jié)構(gòu)體創(chuàng)建了一個用來表示索引值三倍的實例。數(shù)值3作為結(jié)構(gòu)體構(gòu)造函數(shù)入?yún)⒊跏蓟瘜嵗蓡Tmultiplier。

你可以通過下標(biāo)腳本來得到結(jié)果,比如threeTimesTable[6]。這條語句訪問了threeTimesTable的第六個元素,返回63倍即18。

注意:
TimesTable例子是基于一個固定的數(shù)學(xué)公式。它并不適合開放寫權(quán)限來對threeTimesTable[someIndex]進行賦值操作,這也是為什么附屬腳本只定義為只讀的原因。

下標(biāo)腳本用法

根據(jù)使用場景不同下標(biāo)腳本也具有不同的含義。通常下標(biāo)腳本是用來訪問集合(collection),列表(list)或序列(sequence)中元素的快捷方式。你可以在你自己特定的類或結(jié)構(gòu)體中自由的實現(xiàn)下標(biāo)腳本來提供合適的功能。

例如,Swift 的字典(Dictionary)實現(xiàn)了通過下標(biāo)腳本來對其實例中存放的值進行存取操作。在下標(biāo)腳本中使用和字典索引相同類型的值,并且把一個字典值類型的值賦值給這個下標(biāo)腳本來為字典設(shè)值:

    var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
    numberOfLegs["bird"] = 2

上例定義一個名為numberOfLegs的變量并用一個字典字面量初始化出了包含三對鍵值的字典實例。numberOfLegs的字典存放值類型推斷為Dictionary<String, Int>。字典實例創(chuàng)建完成之后通過下標(biāo)腳本的方式將整型值2賦值到字典實例的索引為bird的位置中。

更多關(guān)于字典(Dictionary)下標(biāo)腳本的信息請參考讀取和修改字典

注意:
Swift 中字典的附屬腳本實現(xiàn)中,在get部分返回值是Int?,上例中的numberOfLegs字典通過附屬腳本返回的是一個Int?或者說“可選的int”,不是每個字典的索引都能得到一個整型值,對于沒有設(shè)過值的索引的訪問返回的結(jié)果就是nil;同樣想要從字典實例中刪除某個索引下的值也只需要給這個索引賦值為nil即可。

下標(biāo)腳本選項

下標(biāo)腳本允許任意數(shù)量的入?yún)⑺饕?,并且每個入?yún)㈩愋鸵矝]有限制。下標(biāo)腳本的返回值也可以是任何類型。下標(biāo)腳本可以使用變量參數(shù)和可變參數(shù),但使用寫入讀出(in-out)參數(shù)或給參數(shù)設(shè)置默認(rèn)值都是不允許的。

一個類或結(jié)構(gòu)體可以根據(jù)自身需要提供多個下標(biāo)腳本實現(xiàn),在定義下標(biāo)腳本時通過入?yún)€類型進行區(qū)分,使用下標(biāo)腳本時會自動匹配合適的下標(biāo)腳本實現(xiàn)運行,這就是下標(biāo)腳本的重載。

一個下標(biāo)腳本入?yún)⑹亲畛R姷那闆r,但只要有合適的場景也可以定義多個下標(biāo)腳本入?yún)?。如下例定義了一個Matrix結(jié)構(gòu)體,將呈現(xiàn)一個Double類型的二維矩陣。Matrix結(jié)構(gòu)體的下標(biāo)腳本需要兩個整型參數(shù):

    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提供了一個兩個入?yún)⒌臉?gòu)造方法,入?yún)⒎謩e是rowscolumns,創(chuàng)建了一個足夠容納rows * columns個數(shù)的Double類型數(shù)組。為了存儲,將數(shù)組的大小和數(shù)組每個元素初始值0.0,都傳入數(shù)組的構(gòu)造方法中來創(chuàng)建一個正確大小的新數(shù)組。關(guān)于數(shù)組的構(gòu)造方法和析構(gòu)方法請參考創(chuàng)建并且構(gòu)造一個數(shù)組。

你可以通過傳入合適的rowcolumn的數(shù)量來構(gòu)造一個新的Matrix實例:

    var matrix = Matrix(rows: 2, columns: 2)

上例中創(chuàng)建了一個新的兩行兩列的Matrix實例。在閱讀順序從左上到右下的Matrix實例中的數(shù)組實例grid是矩陣二維數(shù)組的扁平化存儲:

http://wiki.jikexueyuan.com/project/swift-language-guide/images/Subscripts_1.png" alt="Image of Subscripts_1.png" />

將值賦給帶有rowcolumn下標(biāo)腳本的matrix實例表達(dá)式可以完成賦值操作,下標(biāo)腳本入?yún)⑹褂枚禾柗指?/p>

    matrix[0, 1] = 1.5
    matrix[1, 0] = 3.2

上面兩條語句分別讓matrix的右上值為 1.5,坐下值為 3.2:

http://wiki.jikexueyuan.com/project/swift-language-guide/images/Subscripts_2.png" alt="Image of Subscripts_2.png" />

Matrix下標(biāo)腳本的gettersetter中同時調(diào)用了下標(biāo)腳本入?yún)⒌?code>row和column是否有效的判斷。為了方便進行斷言,Matrix包含了一個名為indexIsValid的成員方法,用來確認(rèn)入?yún)⒌?code>row或column值是否會造成數(shù)組越界:

    func indexIsValidForRow(row: Int, column: Int) -> Bool {
        return row >= 0 && row < rows && column >= 0 && column < columns
    }

斷言在下標(biāo)腳本越界時觸發(fā):

    let someValue = matrix[2, 2]
    // 斷言將會觸發(fā),因為 [2, 2] 已經(jīng)超過了matrix的最大長度