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