【发布时间】:2018-10-21 08:00:04
【问题描述】:
作为 Swift 的一个练习,我正在尝试编写一个扩展方法来解开任意深度嵌套的选项。 这没什么实际用处,只是对 Swift 类型系统的探索。
任意深度嵌套的可选项的示例是 Optional<Optional<Optional<Int>>> 和 Optional<Optional<Optional<Optional<Int>>>>。
我发现这样做的唯一方法是使用类型擦除:
protocol TypeErasedOptional {
func deeplyUnwrap() -> Any?
}
extension Optional: TypeErasedOptional {
func deeplyUnwrap() -> Any? {
switch self {
case .none: return nil
case .some(let wrapped as TypeErasedOptional): return wrapped.deeplyUnwrap()
case .some(let wrapped): return wrapped
}
}
func unwrap<T>(_ type: T.Type = T.self) -> T? {
switch deeplyUnwrap() {
case .none: return nil
case .some(let wrapped as T): return wrapped
default: return nil
}
}
}
这很好用。我们可以解开一个深度嵌套的可选项,但不幸的是我们必须重述Wrapped 类型:
let x = Optional<Optional<Optional<Int>>>(3)
let y = x.unwrap(Int.self)
如果没有类型擦除,我想不出任何方法来做到这一点。一旦你使用类型擦除,你必须重述类型以取回它。我不想要这个。是否可以让更精通 Swift 的人告诉我这无法完成或是否有其他方法?
【问题讨论】:
-
Swift 的铸造机械可以钻透任意级别的可选性,所以你可以说
let y = x as? Int:) -
@Hamish 我很清楚!但这不会那么有趣。
-
很公平 - 我很确定如果不以某种方式重新声明
Wrapped类型,您将无法实现这一点,因为您无法递归展开通用占位符(即你不能表达“如果Wrapped类型是Optional,递归考虑它的Wrapped类型”)。 -
为了好玩,您可以创建自己的包装器类型来跟踪原始包装值 (gist.github.com/hamishknight/e08e97f3170f8f30f8ca9df21a6ec365),但这可能不是您的想法;)
-
这在 Swift 4.1+ 中更有用,编译器不再自动完全解开嵌套的选项。