swift - 向扩展中的泛型参数添加约束

标签 swift generics dictionary swift2 swift-extensions

我有这个功能:

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>'

最佳答案

在 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 中指定确切的类型协议(protocol)扩展的子句,一种您可以准确检测到 Optional 的方法类型是制作Optional唯一地符合协议(protocol)(例如 OptionalEquivalent )。

为了得到Optional的包装值类型, 我定义了一个类型别名 WrappedValueType在自定义协议(protocol)中 OptionalEquivalent然后对 Optional 进行扩展,分配 WrappedWrappedValueType , 然后就可以在flatten方法中得到type。

请注意 sugarCast方法只是转换 Optional<Wrapped>Wrapped? (这是完全一样的东西),以启用使用 guard声明。

更新

感谢 Rob Napier 的评论,我简化并重命名了 sugarCast() 方法并重命名了协议(protocol)以使其更易于理解。

关于swift - 向扩展中的泛型参数添加约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33436199/

相关文章:

JavaScript 函数参数 : positional -> map transition

java - 在 java 中使用 HashMap 的主要好处是什么?

string - Swift,使用字符串名称来引用变量

ios - 在 Pod 更新后将事件插入日历时,Google Calendar API 会出现 404 错误。

swift - 往返数据的往返 Swift 数字类型

ios - 如何使用结果库处理 Void 成功案例(成功/失败)

c# - 抽象工厂模式而不是泛型——怎么样?

ios - 函数获取 <T :EVObject>(){}

c# - 对通用接口(interface)的抽象引用

java - 有界扩展枚举参数的通用方法 - 无法访问 values() 方法