我正试图编写一个函数来打开具有任意嵌套级别的选项。这是我正在使用的测试:
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??
的有效值,因此不会返回默认值。
有什么办法可以安全地在这里做我想做的事吗?
此代码满足您的要求缺点是您需要在要放入选项的每种类型中实现Unwrappeable协议。也许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
诀窍在于,Unwrappeable协议将最终可以展开的类型(如在0、1或更多个展开之后(标记为特定类型。
这个问题的困难在于,在Optional的扩展中,您可以获得Wrapped类型,但如果Wrapped再次是可选的,则无法访问Wrapped。Wrapped(换句话说,Swift不支持Higher Kinded Types(。
另一种方法是尝试向Optional where Wrapped == Optional
添加一个扩展。但同样,您需要更高类型的支持才能访问Wrapped。包装类型。如果我们试图扩展Optional where Wrapped == Optional<T>
,我们也会失败,因为我们不能在T.上一般地扩展Optional