Как сравнить два массива протоколов на равенство в Swift?
Я столкнулся с ситуацией, которая, я уверен, не является такой уж редкостью. У меня есть два массива объектов, которые соответствуют протоколу, и я хочу проверить, равны ли они.
Что я действительно хотел бы сделать, так это:
protocol Pattern: Equatable
{
func isEqualTo(other: Pattern) -> Bool
}
func ==(rhs:Pattern, lhs:Pattern) -> Bool
{
return rhs.isEqualTo(lhs)
}
extension Equatable where Self : Pattern
{
func isEqualTo(other: Pattern) -> Bool
{
guard let o = other as? Self else { return false }
return self == o
}
}
Однако это приводит к ошибке компиляции:
Error:(10, 30) protocol 'Pattern' can only be used as a generic constraint because it has Self or associated type requirements
Основываясь наэтом посте , я понимаю, что мне нужно потерять эквивалентное наследование в моем протоколе и спихнуть его на конкретные объявления "шаблона". Хотя я действительно не понимаю почему?. Если я определяю, как два объекта равны, основываясь на протоколе, перегружая ==, насколько я могу видеть, на самом деле нет никакой проблемы. Мне даже не нужно знать фактические типы или являются ли они классами или структурами.
Несмотря на это, все это хорошо, и теперь я могу сравнить concretePattern.isEqualTo(otherConcretePattern), но проблема остается в том, что я больше не могу сравнивать массивы этих объектов, как я могу сравнить массив конкретного типа, поскольку равенство массивов зависит от перегрузки оператора==.
Лучший Мне удалось сделать это до сих пор-это glom метод isEqualTo на CollectionType через расширение. Это, по крайней мере, позволяет мне сравнивать массивы. Но, честно говоря, этот код воняет.
extension CollectionType where Generator.Element == Pattern
{
func isEqualTo(patterns:[Pattern]) -> Bool {
return self.count as? Int == patterns.count && !zip(self, patterns).contains { !$0.isEqualTo($1) }
}
}
Неужели нет другого способа сделать это? Пожалуйста, скажи мне, что я упускаю что-то очевидное.
2 ответов:
У меня есть два массива объектов, которые соответствуют протоколу, и я хочу проверить, равны ли они.Таким образом, вы хотите сказать, что два массива равны, если все элементы в них равны и все элементы соответствуют шаблону. то естьЕсли a, b, c и d-все вещи, которые соответствуют шаблону, вы хотите
Самый простой способ сделать это-фактически определить оператор равенства для двух массивов шаблонов, т. е.a == c a != b a != d b != d let array1: [Pattern] = [a, b, c] let array2: [Pattern] = [a, b, a] let array3: [Pattern] = [a, d, c] array1 == array2 // true array1 == array3 // falseprotocol Pattern { func isEqualTo(other: Pattern) -> Bool } func ==(rhs: Pattern, lhs: Pattern) -> Bool { return rhs.isEqualTo(lhs) } func ==(lhs: [Pattern], rhs: [Pattern]) -> Bool { guard lhs.count == rhs.count else { return false } var i1 = lhs.generate() var i2 = rhs.generate() var isEqual = true while let e1 = i1.next(), e2 = i2.next() where isEqual { isEqual = e1 == e2 } return isEqual }Я определил два типа, которые соответствовать шаблону и пробовал различные равенства сравнивает и все это работает
struct Foo: Pattern { let data: String init(data: String) { self.data = data } func isEqualTo(other: Pattern) -> Bool { guard let other = other as? Foo else { return false } return self.data == other.data } } struct Bar: Pattern { let data: String init(data: String) { self.data = data } func isEqualTo(other: Pattern) -> Bool { guard let other = other as? Bar else { return false } return self.data == other.data } } let a = Foo(data: "jeremyp") let b = Bar(data: "jeremyp") let c = Foo(data: "jeremyp") let d = Foo(data: "jeremy") let comp1 = a == c // true let comp2 = a == b // false let comp3 = a == d // false let array1: [Pattern] = [a, b, c] let array2: [Pattern] = [a, b, a] let array3: [Pattern] = [a, d, c] let comp4 = array1 == array2 // true let comp5 = array1 == array3 // false
Ответ Swift :
protocol _Pattern { func _isEqualTo(_other: Any) -> Bool? } extension _Pattern where Self: Pattern { func _isEqualTo(_other: Any) -> Bool? { return (_other as? Self).map({ self.isEqualTo($0) }) } } protocol Pattern: _Pattern, Equatable { func isEqualTo(other: Self) -> Bool } extension Pattern { func isEqualTo(other: _Pattern) -> Bool { return _isEqualTo(other) ?? false } } func == <T: Pattern>(rhs: T, lhs: T) -> Bool { return rhs.isEqualTo(lhs) }Это шаблон (каламбур), который я разработал сам, и он очень хорошо работает в подобных ситуациях.
_Patternявляется автоматически реализованным протоколом, любезно предоставленным новой функцией расширения протокола, и представляет собой стираемую версиюPattern.
Comments