如何在Swift中展开任意深度嵌套的选项?

时间:2018-05-11 00:17:28

标签: swift swift4

作为Swift中的一个练习,我正在尝试编写一个扩展方法,它将打开任意深度嵌套的选项。 这几乎没有实际用途,只是对Swift类型系统的探索。

任意深度嵌套的选项的示例包括Optional<Optional<Optional<Int>>>Optional<Optional<Optional<Optional<Int>>>>

我发现这样做的唯一方法是使用类型擦除:

protocol TypeErasedOptional {
    func deeplyUnwrap() -> Any?
}

extension Optional: TypeErasedOptional {
    func deeplyUnwrap() -> Any? {
        switch self {
        case .none: return nil
        case .some(let wrapped as TypeErasedOptional): return wrapped.deeplyUnwrap()
        case .some(let wrapped): return wrapped
        }
    }

    func unwrap<T>(_ type: T.Type = T.self) -> T? {
       switch deeplyUnwrap() {
       case .none: return nil
       case .some(let wrapped as T): return wrapped
       default: return nil
       }
    }
}

这很有效。我们可以解包一个深层嵌套的可选项,但不幸的是我们必须重新设置Wrapped类型:

let x = Optional<Optional<Optional<Int>>>(3)
let y = x.unwrap(Int.self)

如果没有类型擦除,我无法想到任何方法。一旦你使用了类型擦除,你必须重新设置类型才能恢复它。我不想要这个。更精通斯威夫特的人能不能让我知道这不可能做到或者是否有另一种方式?

2 个答案:

答案 0 :(得分:2)

这是一个解决方案,可将展平到六个级别Optional

extension Optional {
    func flatten() -> Wrapped? {
        return self
    }

    func flatten<T>() -> T? where Wrapped == T? {
        return map { $0.flatten() } ?? nil
    }

    func flatten<T>() -> T? where Wrapped == T?? {
        return map { $0.flatten() } ?? nil
    }

    func flatten<T>() -> T? where Wrapped == T??? {
        return map { $0.flatten() } ?? nil
    }

    func flatten<T>() -> T? where Wrapped == T???? {
        return map { $0.flatten() } ?? nil
    }

    func flatten<T>() -> T? where Wrapped == T????? {
        return map { $0.flatten() } ?? nil
    }
}

上述解决方案的优点是类型安全,缺点是它是静态类型的(例如,不能在flatten()变量上调用Any),并且您需要如果需要支持越来越多的嵌套级别,则会添加越来越多的重载。

答案 1 :(得分:0)

Optional.flatMap(_:)似乎可以解决问题。例如:

var a: String??? = "aaa"
let b: String = a?.flatMap{$0} ?? "<nil>"

print(b) // "aaa"

documentation并未明确提及此功能,但可以使用。

编辑:不是,请参见下面的评论。