任何类型的可选扩展

Optional extension for any types

我想为 任何 类型编写 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

有效,但它是 Optional(Int) 扩展 (Optional where Wrapped == Int),我想将此扩展用于 any 类型如 DateStringDouble

你有什么建议?

可选 已经 通用。它已经接受任何类型作为其参数化类型。它的参数化已经 名称:Wrapped。只需说 Wrapped 而不是 T。你的TWrapped.

extension Optional {
    func isNil<Wrapped>(value: Wrapped) -> Wrapped {
        if self != nil {
            return self as! Wrapped
        }
        return value
    }
}

如果出于某种原因您真的更喜欢 T,请使用类型别名。这只是一个名字:

extension Optional {
    typealias T = Wrapped
    func isNil<T>(value: T) -> T {
        if self != nil {
            return self as! T
        }
        return value
    }
}

但在任何情况下,您的扩展都是完全没有必要的,因为 nil-coalescing 运算符 ?? 已经做到了。

var tempInt: Int?
tempInt ?? 2 /// returns 2
tempInt = 5
tempInt ?? 2 /// returns 5

您的基本问题的答案是删除 where 子句:

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

现在它适用于所有选项。

但是这段代码很破烂。如果 TWrapped 不同,它会崩溃。所以你真的是指一个适用于 Wrapped:

的非泛型函数
extension Optional {
    func isNil(value: Wrapped) -> Wrapped {
        if self != nil {
            return self!  // `as!` is unnecessary
        }
        return value
    }
}

但这只是一种详尽的说法 ??(正如马特指出的那样)

extension Optional {
    func isNil(value: Wrapped) -> Wrapped { self ?? value }
}

除了??更强大。它包括一个自动关闭,除非实际使用,否则避免评估默认值,并且可以 throw。在大多数情况下,它也更加惯用Swift。您可以找到 source on 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()
  }
}

但我可以想象您可能会使用基于方法的解决方案的情况(它们很奇怪,但也许有这样的情况)。您只需将其重写为方法即可获得:

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)