编程iOS开发者

解释Swift中下标的工作特性。下标存在哪些限制,如何扩展这一机制以及应该在哪里应用?请给出一个非标准下标的例子。

用 Hintsage AI 助手通过面试

回答

下标在Swift中允许以类似数组或字典的方式通过键或索引访问类型的值,但适用于任何自定义类型。语法类似于函数,但访问是通过括号实现的:object[key]

特性:

  • 类或结构可以具有多个下标(参数重载)。
  • 下标可以是只读或读写(只包含get或同时包含getset)。
  • 下标可以具有任意数量的参数和类型(例如,两个索引)。
  • 不支持变参。

应用:

  • 用于简化对集合、矩阵、自定义对象、可序列化值等的访问。

示例: 二维数组(矩阵)和具有两个参数的下标:

struct Matrix { let rows: Int, columns: Int private 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 { precondition(isValid(row: row, column: column), "索引超出范围") return grid[(row * columns) + column] } set { precondition(isValid(row: row, column: column), "索引超出范围") grid[(row * columns) + column] = newValue } } private func isValid(row: Int, column: Int) -> Bool { return row >= 0 && row < rows && column >= 0 && column < columns } } var matrix = Matrix(rows: 2, columns: 2) matrix[0,1] = 5.0 print(matrix[0,1]) // 5.0

陷阱问题

下标是否可以具有类型为inout的参数或在结构体中是mutating的?

回答:

  • 下标参数不能是inout
  • 在值类型(struct/enum)中,下标可以声明为mutating set,这允许在set内修改self:
struct Counter { var value: Int = 0 subscript(increment: Bool) -> Int { mutating get { value += increment ? 1 : -1 return value } } }

因为不了解该主题的细微差别而造成的实际错误的例子


故事

在自定义集合中忘记将下标设置为mutating,因此通过下标修改元素的任何尝试都会导致编译错误。错误在经过长时间调试后,在集成集合的阶段显现出来。


故事

在自定义下标中未实现对索引越界的正确处理,这导致在超出范围访问时崩溃。因此,影响到了业务关键的数据处理功能。


故事

在枚举中实现了具有两个参数的下标用于缓存,但未考虑到下标不能是static(类型级别的),只能是实例级别的。架构决策被证明是错误的,不得不重写集合的API交互。