在扩展中为通用参数添加约束 [英] Add constraints to generic parameters in extension

查看:124
本文介绍了在扩展中为通用参数添加约束的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这个功能:

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] 一个(不可选) 。

As you can see, it transforms a [Key: Value?] dictionary into a [Key: Value] one (without the optional).

我想使用一个新的方法来扩展 Dictionary 类,其值为任意类型的可选,但我无法添加字典通用参数的限制。

I wanted to extend the Dictionary class with a new method only for classes which value is an Optional of any type, but I am unable to add constraints to the generic parameters of the dictionary.

这是我试过的:

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中尝试此代码:

Try this code in the 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"]

因为您不能在中指定确切的类型, / code>子句的一个协议扩展,一种方法可以精确检测可选类型是使可选 UNIQUELY符合协议(例如 OptionalEquivalent )。

Because you cannot specify an exact type in the where clause of a protocol extension, one way you may detect exactly the Optional type is to make Optional UNIQUELY conforms to a protocol (say OptionalEquivalent).

为了获得可选,我在定制协议中定义了一个typealias WrappedValueType 可选等价然后将可选的扩展名,将 Wrapped 分配到 WrappedValueType ,然后可以获得类型i

In order to get the wrapped value type of the Optional, I defined a typealias WrappedValueType in the custom protocol OptionalEquivalent and then made an extension of Optional, assgin the Wrapped to WrappedValueType, then you can get the type in the flatten method.

请注意, sugarCast 方法只是转换可选< ;包裹> 包裹?(这是完全一样的),启用使用 guard 语句。

Note that the sugarCast method is just to cast the Optional<Wrapped> to Wrapped?(which is exactly the same thing), to enable the usage guard statement.

更新

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

Thanks to Rob Napier 's comment I have simplified & renamed the sugarCast() method and renamed the protocol to make it more understandable.

这篇关于在扩展中为通用参数添加约束的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆