我遇到了一种情况,我确信这种情况并不少见。我有两个符合协议的对象数组,我想检查它们是否相等。
我真正想做的是:
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
基于这篇文章,我意识到我需要失去协议上的 Equatable 继承,并将其下推到具体的“模式”声明中。虽然我真的不明白为什么。如果我通过重载 == 根据协议定义这两个对象如何相等,那么据我所知,这确实没有问题。我什至不需要知道实际的类型或者它们是类还是结构。
无论如何,这一切都很好,我现在可以比较concretePattern.isEqualTo(otherConcretePattern)
,但问题仍然是我不能再比较这些对象的数组,就像我可以比较具体类型的数组一样,因为数组相等依赖于重载 == 运算符。
到目前为止,我设法做的最好的事情是通过扩展将一个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) }
}
}
真的没有其他方法可以做到这一点吗?请告诉我我遗漏了一些明显的东西。