swift2 将约束添加到扩展中泛型参数

vshtjzan  于 2022-11-06  发布在  Swift
关注(0)|答案(2)|浏览(263)

我有这个功能:

func flatten<Key: Hashable, Value>(dict: Dictionary<Key, Optional<Value>>) -> Dictionary<Key, Value> {
    var result = [Key: Value]()
    for (key, value) in dict {
        guard let value = value else { continue }
        result[key] = value
    }
    return result
}

如您所见,它将[Key: Value?]字典转换为[Key: Value]字典(没有可选的)。
我想用一个新的方法扩展Dictionary类,只用于值为任何类型的Optional的类,但是我无法向字典的泛型参数添加约束。
这就是我所尝试的:

extension Dictionary where Value: Optional<Any> {
    func flatten() -> [Key: Any] {
        var result = [Key: Any]()
        for (key, value) in self {
            guard let value = value else { continue }
            result[key] = value
        }
        return result
    }
}

但失败并出现错误:

Type 'Value' constrained to non-protocol type 'Optional<Any>'
xxslljrj

xxslljrj1#

在Playground中尝试以下代码:

// make sure only `Optional` conforms to this protocol
protocol OptionalEquivalent {
  typealias WrappedValueType
  func toOptional() -> WrappedValueType?
}

extension Optional: OptionalEquivalent {
  typealias WrappedValueType = Wrapped

  // just to cast `Optional<Wrapped>` to `Wrapped?`
  func toOptional() -> WrappedValueType? {
    return self
  }
}

extension Dictionary where Value: OptionalEquivalent {
  func flatten() -> Dictionary<Key, Value.WrappedValueType> {
    var result = Dictionary<Key, Value.WrappedValueType>()
    for (key, value) in self {
      guard let value = value.toOptional() else { continue }
      result[key] = value
    }
    return result
  }
}

let a: [String: String?] = ["a": "a", "b": nil, "c": "c", "d": nil]
a.flatten() //["a": "a", "c": "c"]

因为您无法在通信协定扩充的where子句中指定确切的类型,所以您可以精确侦测Optional类型的一种方式是让Optional“唯一”符合通信协定(例如OptionalEquivalent)。
为了得到Optional的 Package 值类型,我在自定义协议OptionalEquivalent中定义了一个typealias WrappedValueType,然后对Optional进行了扩展,将Wrapped赋值给WrappedValueType,然后就可以在flat方法中得到该类型。
请注意,sugarCast方法只是将Optional<Wrapped>转换为Wrapped?(完全相同),以启用guard语句的用法。

更新

多亏了Rob纳皮耶的评论,我已经简化并重命名了sugarCast()方法,并重命名了协议,使其更容易理解。

mrwjdhj3

mrwjdhj32#

你可以用一种更简单的方法来做,这适用于Swift 4:

extension Dictionary {
    func flatten<Wrapped>() -> [Key: Wrapped] where Value == Optional<Wrapped> {
         return filter { $1 != nil }.mapValues { $0! }
    }
}

如果你不喜欢使用高阶函数或需要与Swift的早期版本兼容,你也可以这样做:

extension Dictionary {
    func flatten<Wrapped>() -> [Key: Wrapped] where Value == Optional<Wrapped> {
        var result: [Key: Wrapped] = [:]
        for (key, value) in self {
            guard let value = value else { continue }
            result[key] = value
        }
        return result
    }
}

相关问题