Swift 中的下标机制自 2014 年语言问世以来就已引入,旨在以更便捷的语法访问集合的数据。下标允许通过方括号访问数组、字典和其他集合的元素。现代 Swift 允许为自定义类型创建用户自定义下标,使 API 直观易懂,就像标准数据结构一样。
问题: 以前的访问方法看起来更加繁琐(例如,通过 .getElement(at: )),而下标使与类型的交互更为简洁。然而,错误的实现可能导致低效的代码或访问集合边界之外的错误。
解决方案: 要实现下标,使用关键字 subscript,然后指定参数和返回值。下标可以是只读的,也可以是读写的。此外,下标可以为不同的参数进行重载。
代码示例:
struct Matrix { let rows: Int let columns: Int var grid: [Double] init(rows: Int, columns: Int) { self.rows = rows self.columns = columns self.grid = Array(repeating: 0.0, count: rows * columns) } subscript(row: Int, column: Int) -> Double { get { assert(row >= 0 && row < rows && column >= 0 && column < columns, "Index out of range") return grid[(row * columns) + column] } set { assert(row >= 0 && row < rows && column >= 0 && column < columns, "Index out of range") grid[(row * columns) + column] = newValue } } } var matrix = Matrix(rows: 2, columns: 2) matrix[0, 1] = 3.14 print(matrix[0, 1]) // 3.14
关键特性:
下标可以只读吗?还是下标必须始终有 get 和 set?
如果在实现中没有 set,则下标可以是只读的(仅 get)。不必实现两个访问器,这与属性类似。
代码示例:
subscript(index: Int) -> Int { get { return index * 2 } }
可以通过 inout 在下标中传递可变参数吗?
不可以,下标不支持在签名中使用 inout 参数。所有下标的参数均在访问器体内作为 let 常量接收。
下标可以返回可选类型吗?
可以,下标可以返回可选值,这在安全访问集合元素时非常方便,无需担心超出数组范围。
代码示例:
extension Array { subscript(safe index: Int) -> Element? { return indices.contains(index) ? self[index] : nil } }
在复合类型矩阵的实现中,没有对下标进行边界验证,导致索引错误时应用崩溃。
优点:
缺点:
添加了安全索引的可选版本的下标,处理错误,使 API 明确且安全。
优点:
缺点: