问题背景:
Subscript 是一个机制,可以通过方括号访问集合、结构和其他类型中的值。它在 Swift 中的引入是借鉴了其他语言(例如 Python 中的数组索引,C++/Java 中的 [] 运算符),旨在使处理集合和类似对象的工作更加直观。
问题:
并不是所有类型都默认支持像数组一样的索引访问。当我们有一个带数据的结构或类时,通过熟悉的语法(如 myObject[index])访问元素通常是更合乎逻辑的,而不是通过方法。
解决方案:
Swift 允许为任何用户定义的类型自行实现 subscript。可以创建仅用于读取或同时用于读取和写入的 subscript。以下是实现针对平方矩阵进行操作的 subscript 的结构示例:
struct Matrix { let size: Int private var grid: [Int] init(size: Int) { self.size = size self.grid = Array(repeating: 0, count: size * size) } subscript(row: Int, column: Int) -> Int { get { precondition(indexIsValid(row, column), "索引超出范围") return grid[(row * size) + column] } set { precondition(indexIsValid(row, column), "索引超出范围") grid[(row * size) + column] = newValue } } private func indexIsValid(_ row: Int, _ column: Int) -> Bool { return row >= 0 && row < size && column >= 0 && column < size } } var m = Matrix(size: 3) m[1,2] = 7 print(m[1,2]) // 7
关键特点:
Subscript 只能用于集合吗?
不,subscript 可以为任何类型实现:结构、类、枚举。内部数据类型不必是集合,主要在于通过 subscript 处理请求的逻辑。
一个类型中可以有多个不同签名的 subscript 吗?
可以,允许在参数签名不同的情况下重载 subscript:
struct Example { subscript(index: Int) -> Int { return index } subscript(key: String) -> String { return key.uppercased() } }
可以将 subscript 作为没有 set 的计算属性使用吗?
可以,subscript 可以仅用于读取(仅获取),那么写入尝试将导致编译错误。
struct ReadOnly { subscript(index: Int) -> Int { index * index } }
在一个大型结构中实现了一个没有范围检查的 subscript,导致在索引不正确时应用崩溃。
优点:
缺点:
Matrix 通过对索引范围的 precondition 实现。任何错误都会立即捕获,不会进入生产环境。
优点:
缺点: