4

我正在尝试编写一个函数来解开具有任意数量嵌套级别的选项。这是我正在使用的测试:

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??因此它不会返回默认值。

有什么方法可以安全地做我想做的事吗?

4

1 回答 1

1

这段代码可以满足您的要求。缺点是您需要在要放入 optionals 的每种类型中实现 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 不支持 Higher Kinded类型)。

另一种方法是尝试向Optional where Wrapped == Optional. 但同样,您需要更高种类的类型支持才能访问 Wrapped.Wrapped 类型。如果我们尝试扩展Optional where Wrapped == Optional<T>,我们也会失败,因为我们不能在 T 上通用扩展 Optional。

于 2018-11-07T10:32:36.127 回答