Ответ 1
Попробуйте этот код на игровой площадке:
// 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
UNIQUELY соответствующим протоколу (скажем OptionalEquivalent
).
Чтобы получить тип обернутого значения Optional
, я определил typealias WrappedValueType
в пользовательском протоколе OptionalEquivalent
, а затем сделал расширение необязательным, отвяжите Wrapped
до WrappedValueType
, затем вы можете получить тип в методе сглаживания.
Обратите внимание, что метод sugarCast
предназначен только для того, чтобы отнести Optional<Wrapped>
к Wrapped?
(что точно так же), чтобы включить оператор guard
.
UPDATE
Благодаря комментарию Роба Напира я упростил и переименовал метод sugarCast() и переименовал протокол, чтобы сделать его более понятным.