我有这个功能:
- 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类,只有这个类的值是任何类型的可选项,但是我无法为字典的通用参数添加约束.
这是我试过的:
- 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>'
在游乐场尝试此代码:
- // 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子句中指定确切类型,所以您可以精确检测可选类型的一种方法是使可选UNIQUELY符合协议(例如OptionalEquivalent).
为了获取可选的包装值类型,我在自定义协议OptionalEquivalent中定义了一个typealias WrappedValueType,然后将可扩展的可扩展名,将“Wrapped”绑定到WrappedValueType,然后可以在flatten方法中获取类型.
请注意,sugarCast方法只是将可选的< Wrapped>要包装?(这是完全一样的),以启用使用保护语句.
UPDATE