我正在尝试编写一个函数来解包具有任意嵌套级别的可选值。这是我正在使用的测试:
let a: Int??? = 1
let b: Int??? = nil
print(a.unwrap(0), b.unwrap(0)) // should print 1, 0
我可以用一个基本的泛型函数得到正确的输出:
extension Optional {
func unwrap<T> (_ defaultValue: T) -> T {
return (self as? T) ?? defaultValue
}
}
print(a.unwrap(0), b.unwrap(0)) // 1, 0
但这并不能阻止使用与可选类型不同的类型调用该函数。例如,我可以调用 a.unwrap("foo")
,它会打印“foo”而不是“1”,因为你当然不能转换 Int???
到 String
。
我尝试使用 Wrapped
代替,它半正确地限制了默认值但没有给出正确的输出:
extension Optional {
func unwrap (_ defaultValue: Wrapped) -> Wrapped {
return (self as? Wrapped) ?? defaultValue
}
}
print(a.unwrap(0), b.unwrap(0)) // Optional(Optional(1)), nil
它只解包可选的一层,而不是所有三层,并且由于 nil 是 Int??
的有效值,它不会返回默认值。
有什么方法可以安全地做我想做的事吗?
最佳答案
此代码可以满足您的要求。 缺点是您需要在每个要放入可选类型的类型中实现 Unwrappable 协议(protocol)。也许Sourcery可以提供帮助。
protocol Unwrappable {
associatedtype T
func unwrap(_ default: T) -> T
}
extension Optional {}
extension Optional: Unwrappable where Wrapped: Unwrappable {
typealias T = Wrapped.T
func unwrap(_ defaultValue: T) -> T {
if let value = self {
return value.unwrap(defaultValue)
}
return defaultValue
}
}
extension Int: Unwrappable {
typealias T = Int
func unwrap(_ default: Int) -> Int {
return self
}
}
let nestedOptionalValue: Int??? = 6
let nestedOptionalNil: Int??? = nil
let optionalValue: Int? = 6
let optionalNil: Int? = nil
print(nestedOptionalValue.unwrap(0)) // prints 6
print(nestedOptionalNil.unwrap(0)) // prints 0
print(optionalValue.unwrap(0)) // prints 6
print(optionalNil.unwrap(0)) // prints 0
诀窍在于 Unwrappable 协议(protocol)将最终可以解包(如在 0、1 或更多解包之后)的类型标记为特定类型。
这个问题的难点在于,在对 Optional 的扩展中,你可以获得 Wrapped 类型,但是如果 Wrapped 再次是可选的,你就无法访问 Wrapped.Wrapped(换句话说,Swift 不支持更高种类的类型)。
另一种方法是尝试向 Optional where Wrapped == Optional
添加扩展名.但是同样,您需要 Higher Kinded Types 支持才能访问 Wrapped.Wrapped 类型。如果我们尝试扩展 Optional where Wrapped == Optional<T>
,我们也失败了,因为我们不能在 T 上扩展 Optional。
关于swift - 展开/合并多级可选,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53182664/