Unwrap/coalesce 多级可选
Unwrap/coalesce a multi-level optional
我正在尝试编写一个函数来解包具有任意嵌套级别的可选值。这是我正在使用的测试:
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??
的有效值,所以它不是 return 默认值。
有什么方法可以安全地做我想做的事吗?
这段代码可以满足您的要求。 缺点是你需要在每个你想放入可选的类型中实现 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又是optional,就无法访问Wrapped.Wrapped(换句话说, Swift 不支持高等类型。
另一种方法是尝试向 Optional where Wrapped == Optional
添加扩展名。但是同样,您需要高级类型支持才能访问 Wrapped.Wrapped 类型。如果我们尝试扩展 Optional where Wrapped == Optional<T>
,我们也会失败,因为我们不能在 T.
上扩展 Optional。
我正在尝试编写一个函数来解包具有任意嵌套级别的可选值。这是我正在使用的测试:
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??
的有效值,所以它不是 return 默认值。
有什么方法可以安全地做我想做的事吗?
这段代码可以满足您的要求。 缺点是你需要在每个你想放入可选的类型中实现 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又是optional,就无法访问Wrapped.Wrapped(换句话说, Swift 不支持高等类型。
另一种方法是尝试向 Optional where Wrapped == Optional
添加扩展名。但是同样,您需要高级类型支持才能访问 Wrapped.Wrapped 类型。如果我们尝试扩展 Optional where Wrapped == Optional<T>
,我们也会失败,因为我们不能在 T.