适用于任何类型的可选扩展

emr*_*tci 7 generics swift swift-extensions option-type

我想为任何Optional类型编写扩展。

我的整数代码:

extension Optional where Wrapped == Int {

    func ifNil<T>(default: T) -> T {
        if self != nil {
            return self as! T
        }
        return default
    }
}

var tempInt: Int?

tempInt.ifNil(default: 2) // returns 2

tempInt = 5

tempInt.ifNil(default: 2) // returns 5
Run Code Online (Sandbox Code Playgroud)

它可以工作,但它是Optional(Int)扩展名 ( Optional where Wrapped == Int),我想将此扩展名用于任何类型Date,例如StringDouble等。

您有什么建议?

Rob*_*ier 7

您的基本问题的答案是删除该where条款:

extension Optional { 
    // ... the rest is the same 
    func isNil<T>(value: T) -> T {
        if self != nil {
            return self as! T
        }
        return value
    }
}
Run Code Online (Sandbox Code Playgroud)

现在它适用于所有选项。

但这段代码很糟糕。T如果与 不同,它会崩溃Wrapped。所以你真正的意思是一个适用于的非泛型函数Wrapped

extension Optional {
    func isNil(value: Wrapped) -> Wrapped {
        if self != nil {
            return self!  // `as!` is unnecessary
        }
        return value
    }
}
Run Code Online (Sandbox Code Playgroud)

但这只是一种复杂的说法??(正如马特指出的)

extension Optional {
    func isNil(value: Wrapped) -> Wrapped { self ?? value }
}
Run Code Online (Sandbox Code Playgroud)

除此之外,它的??威力要大得多。它包含一个自动闭包,可以避免评估默认值,除非实际使用它,并且可以throw。在大多数情况下,它也是更惯用的 Swift。您可以在 github 上找到源代码。

public func ?? <T>(optional: T?, defaultValue: @autoclosure () throws -> T)
    rethrows -> T {
  switch optional {
  case .some(let value):
    return value
  case .none:
    return try defaultValue()
  }
}
Run Code Online (Sandbox Code Playgroud)

但我可以想象您可能会使用基于方法的解决方案的情况(它们很奇怪,但也许存在这种情况)。您可以通过将其重写为方法来实现:

extension Optional {
    public func value(or defaultValue: @autoclosure () throws -> Wrapped) rethrows -> Wrapped {
        switch self {
        case .some(let value):
            return value
        case .none:
            return try defaultValue()
        }
    }
}

tempInt.value(or: 2)
Run Code Online (Sandbox Code Playgroud)