Swift 下标脚本基础概念

下标脚本(Subscripts)是 Swift 中一种特殊语法,允许通过索引或键值快速访问集合、列表或自定义类型的元素。下标脚本可以定义为实例方法或类型方法,语法类似于计算属性。

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)
    }
    
    subscript(row: Int, column: Int) -> Double {
        get {
            return grid[(row * columns) + column]
        }
        set {
            grid[(row * columns) + column] = newValue
        }
    }
}

var matrix = Matrix(rows: 2, columns: 2)
matrix[0, 1] = 1.5  // 调用下标脚本的 setter
print(matrix[0, 1])  // 输出: 1.5

多维下标脚本实现

下标脚本支持多参数,适用于多维数据结构。以下示例展示了一个三维数组的下标脚本实现:

struct ThreeDArray {
    var data: [[[Int]]]
    
    init(x: Int, y: Int, z: Int) {
        data = Array(repeating: Array(repeating: Array(repeating: 0, count: z), count: y), count: x)
    }
    
    subscript(x: Int, y: Int, z: Int) -> Int {
        get { return data[x][y][z] }
        set { data[x][y][z] = newValue }
    }
}

var array3D = ThreeDArray(x: 2, y: 2, z: 2)
array3D[1, 0, 1] = 42
print(array3D[1, 0, 1])  // 输出: 42

类型下标脚本(静态下标)

Swift 5.1 引入了类型下标脚本(static subscript),允许通过类型本身而非实例访问下标:

enum Planet: Int {
    case mercury = 1, venus, earth, mars
    
    static subscript(n: Int) -> Planet? {
        return Planet(rawValue: n)
    }
}

let planet = Planet[3]  // 返回 Optional(Planet.earth)
print(planet!)          // 输出: earth

下标脚本重载

同一个类型可以定义多个下标脚本,通过参数类型或数量区分。以下示例展示字符串通过整型索引或范围访问子串:

extension String {
    subscript(index: Int) -> Character {
        return self[self.index(startIndex, offsetBy: index)]
    }
    
    subscript(range: Range<Int>) -> Substring {
        let start = index(startIndex, offsetBy: range.lowerBound)
        let end = index(startIndex, offsetBy: range.upperBound)
        return self[start..<end]
    }
}

let str = "Swift"
print(str[2])           // 输出: i
print(str[1..<4])       // 输出: wif

下标脚本与泛型结合

下标脚本可以结合泛型实现更灵活的访问逻辑。以下示例展示了一个泛型栈的下标脚本实现:

struct Stack<Element> {
    private var elements = [Element]()
    
    mutating func push(_ element: Element) {
        elements.append(element)
    }
    
    mutating func pop() -> Element? {
        return elements.popLast()
    }
    
    subscript(index: Int) -> Element? {
        guard index < elements.count else { return nil }
        return elements[index]
    }
}

var stack = Stack<String>()
stack.push("Apple")
stack.push("Banana")
print(stack[1]!)  // 输出: Banana

下标脚本的最佳实践

  • 明确用途:下标脚本应专注于简化数据访问,避免包含复杂业务逻辑。
  • 参数命名:使用 rowcolumn 等语义化参数名提升可读性。
  • 错误处理:通过返回可选值或断言处理无效索引,避免崩溃。
struct SafeArray<T> {
    private var array: [T]
    
    init(_ array: [T]) {
        self.array = array
    }
    
    subscript(index: Int) -> T? {
        return index < array.count ? array[index] : nil
    }
}

let safeArray = SafeArray([1, 2, 3])
print(safeArray[5] ?? "Index out of bounds")  // 输出: Index out of bounds

更多推荐