在扩展中为通用参数添加约束 [英] Add constraints to generic parameters in extension
问题描述
我有这个功能:
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屋!