如何限制Array扩展仅适用于元素为非可选类型的数组?
让Array的safe下标只对非可选元素数组生效
想让你写的这个safe下标只给元素是非可选类型的数组用,同时让存可选元素的数组一调用就触发编译错误?可以通过给可选元素数组加个同名但标记为不可用的下标来实现,步骤如下:
- 先定义个标识可选类型的协议
搞一个空协议OptionalType,让Swift自带的Optional类型自动遵循它:
protocol OptionalType { associatedtype Wrapped } extension Optional: OptionalType {}
- 给所有数组加基础的safe下标
先实现通用版的safe下标:
extension Array { subscript(safe index: Int) -> Element? { return indices ~= index ? self[index] : nil } }
- 给可选元素数组加个不可用的同名下标
针对元素是可选类型的数组,加一个同名但标记为unavailable的下标——编译器会优先匹配这个约束更具体的扩展,直接触发编译错误:
extension Array where Element: OptionalType { @available(*, unavailable, message: "别给存可选元素的数组用这个下标!") subscript(safe index: Int) -> Element? { fatalError() // 这里只是凑语法,永远不会执行 } }
试试效果
- 非可选元素数组用起来完全正常:
let normalArray = ["苹果", "香蕉", "橘子"] let fruit = normalArray[safe: 1] // 正常编译,返回"香蕉" let noFruit = normalArray[safe: 5] // 正常编译,返回nil
- 可选元素数组一调用就报错:
let optionalArray = [String?]() optionalArray[safe: 2] // 编译错误:'subscript(safe:)' is unavailable: 别给存可选元素的数组用这个下标!
为啥这么做能行?
Swift匹配扩展的时候,会优先选约束更具体的版本。当数组里存的是可选元素时,会命中那个带where Element: OptionalType的扩展,而这个扩展里的下标被标记成了不可用,编译器直接就给你报错了,完美达到限制的目的。
内容的提问来源于stack exchange,提问作者Kqtr
相关产品推荐
相关产品推荐

