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。