下标基础
下标可以定义在类、结构体和枚举中,是访问集合、列表或序列中元素的快捷方式。下标语法类似于计算属性,使用 subscript
关键字定义。
swift
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int { // 只读下标
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
print(threeTimesTable[6]) // 输出 18
读写下标
下标可以同时包含 getter 和 setter:
swift
struct Matrix {
var grid: [Double]
let rows: Int, columns: Int
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 {
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
}
}
func indexIsValid(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
}
var matrix = Matrix(rows: 2, columns: 2)
matrix[0, 1] = 1.5 // 调用 setter
print(matrix[1, 0]) // 调用 getter
下标特性
多参数下标:
swiftsubscript(row: Int, column: Int) -> Double { ... }
类型下标(静态下标):
swiftenum Planet: Int { case mercury = 1, venus, earth, mars static subscript(n: Int) -> Planet { return Planet(rawValue: n)! } } let mars = Planet[4] // 调用类型下标
下标重载:
swiftstruct Path { private var points: [CGPoint] // 通过索引访问 subscript(index: Int) -> CGPoint { return points[index] } // 通过名称访问 subscript(name: String) -> CGPoint? { return points.first { $0.name == name } } }
实际应用
字典访问:
swiftvar legs = ["ant": 6, "snake": 0] legs["human"] = 2 // 调用字典的下标setter print(legs["ant"]!) // 调用getter
安全数组访问:
swiftstruct SafeArray { private var array: [Int] subscript(index: Int, default defaultValue: Int = 0) -> Int { return indices.contains(index) ? array[index] : defaultValue } }
多维数据结构:
swiftstruct Cube { // 三维下标访问 subscript(x: Int, y: Int, z: Int) -> Int { ... } }
关键注意事项
字典下标返回可选值:
swiftlet value = legs["unicorn"] // Int?
断言检查:
swiftassert(indexIsValid(row: row, column: column), "Index out of range")
性能考虑:
- 避免在下标中进行复杂计算
- 考虑使用缓存优化重复访问
与函数区别:
- 下标不能使用 inout 参数
- 不支持默认参数值(但可以通过重载模拟)
高级用法
动态成员查找(Swift 4.2+):
swift@dynamicMemberLookup struct DynamicStruct { subscript(dynamicMember member: String) -> String { return "Accessed \(member)" } } let s = DynamicStruct() print(s.hello) // 输出 "Accessed hello"
类型约束下标:
swiftstruct GenericContainer<T> { subscript<U: Numeric>(index: U) -> T { ... } }
通过合理使用下标,可以大大提升代码的可读性和简洁性,特别是在处理集合类数据结构时。下标的设计应当保持直观,符合使用者的预期。