Conditional Conformance (условное соответствие) — это мощная фича Swift, позволяющая типам соответствовать протоколу только при выполнении определенных условий. Это особенно полезно для generic-типов.
Условное соответствие позволяет объявить, что generic-тип соответствует протоколу только когда его параметры типа удовлетворяют определенным требованиям.
extension GenericType: SomeProtocol where TypeParameter: SomeCondition {
// реализация требований протокола
}
Пример: сделаем массив Equatable, если его элементы Equatable
extension Array: Equatable where Element: Equatable {
static func ==(lhs: Array, rhs: Array) -> Bool {
guard lhs.count == rhs.count else { return false }
for (l, r) in zip(lhs, rhs) {
if l != r { return false }
}
return true
}
}
struct Box<T> {
let value: T
}
extension Box: Equatable where T: Equatable {
static func ==(lhs: Box, rhs: Box) -> Bool {
return lhs.value == rhs.value
}
}
Без conditional conformance пришлось бы:
protocol JSONRepresentable {
func toJSON() -> String
}
extension Array: JSONRepresentable where Element: JSONRepresentable {
func toJSON() -> String {
let items = self.map { $0.toJSON() }
return "[\(items.joined(separator: ", "))]"
}
}
extension Collection where Element: Numeric {
func sum() -> Element {
return reduce(0, +)
}
}
Optional
соответствует Equatable
, Hashable
и др., если Wrapped тип соответствуетArray
, Dictionary
, Set
соответствуют различным протоколам при выполнении условий для их элементовРекурсивные требования:
Множественные условия:
&
extension Container: SomeProtocol
where Element: Equatable & Hashable {
// ...
}
Реализация универсального кэша:
protocol Cacheable {
associatedtype Key: Hashable
associatedtype Value
func get(_ key: Key) -> Value?
func set(_ value: Value, for key: Key)
}
extension Dictionary: Cacheable where Key: Hashable {
func get(_ key: Key) -> Value? {
return self[key]
}
func set(_ value: Value, for key: Key) {
self[key] = value
}
}
Swift использует conditional conformance для:
Conditional Conformance — это мощный механизм Swift, который позволяет generic-типам автоматически получать функциональность протоколов при выполнении условий для их параметров. Это улучшает переиспользование кода, делает APIs более выразительными и позволяет системе типов работать более эффективно. Особенно полезно для коллекций, optional-типов и других абстракций, где поведение логически зависит от типов-параметров.