Swift Subscripts 的兩三事

下標腳本的特性:

  • 可定義在類別(class)、結構(structure)和列舉(enumeration)
  • 可自行實作並用來存取 collecitons, list or sequences 元素的捷徑
  • 可簡寫成 somearray[index]
  • 單一個目標內可以定義多個 subscripts

下標腳本語法

語法範例

// 一般 stored property 的寫法
subscript(index: Int) -> Int {
    get { }
    // newValue 為 setter 的預設帶入值
    set(newValue) { }
}

// read-only computed property 也可以直接寫
subscript(index: Int) -> Int {
    ... 
}

// 調用的時候就可簡寫成
somearray[0]
somearray[1]

下標腳本用法

可在 collecitons, list or sequences 自行定義存取的方式,例如 Swift 的 dictionary 就實作了通過下標腳本來對其實例中存放的值進行存取

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

下標腳本選項

Subscripts 定義的方式類似於 functions

  • 可以接受各種不同類型的參數,包含不限數量(variadic)類型 (Int..., Double..., etc.)
  • 但不接受 in-out 參數或提供默認預設值
struct MySubscripts {
    subscript(column: Int, row: Int) -> (Int, Int) {
        (column + 1, row + 1)
    }
}
let s = MySubscripts()
print("subscript: \(s[0, 0])")
// subscript: (1, 1)

官方提供一個 Matrix 的範例來展示 Subscripts 的強大之處

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
        }
    }
}

var matrix = Matrix(rows: 2, columns: 2)
// 如果想取得範圍外的元素 assertion 就會擋住
let someValue = matrix[2, 2]

類型下標腳本

實例下標可回傳指定類型。稱為類型下標(Type Subscripts)

  • struct, enum 可設為 static
  • class 的話則可以使用 class 替代

例如下面 week 的 struct

enum Week: Int {
    case monday = 1, tuesday, wednesday, thursday, friday, saturday, sunday
    // type subscrtpts 回傳 Week 這個類型
    static subscript(n: Int) -> Week {
        Week(rawValue: n)!
    }
}
let w = Week[3]
print("\(w)") // wednesday

Reference

comments powered by Disqus