首页 > 解决方案 > Self: Equatable 不起作用的 Swift 协议扩展

问题描述

谁能阐明为什么这不起作用?我收到一个错误Binary operator '==' cannot be applied to operands of type 'Self' and 'CustomEquatable'

protocol CustomEquatable {
    func isEqualTo(_ other: CustomEquatable) -> Bool
}

extension CustomEquatable where Self: Equatable {
    func isEqualTo(_ other: CustomEquatable) -> Bool {
        return self == other
    }
}

标签: swiftgenericsswift-protocols

解决方案


让我们从你的CustomEquatable协议开始,没有扩展:

protocol CustomEquatable {
    func isEqualTo(_ other: CustomEquatable) -> Bool
}

让我们定义一些用于实验的类型:

struct A: Equatable {
    let name: String
}

struct B: Equatable {
    let id: Int
}

假设我们想要AB遵守CustomEquatable。那么我们有四种情况需要考虑:

  • 什么a1.isEqualTo(a2)意思(wherea1a2are both type A)?
  • 什么b1.isEqualTo(b2)意思(whereb1b2are both type B)?
  • 是什么a.isEqualTo(b)意思(哪里a是 aAb是 a B)?
  • 什么b.isEqualTo(a)意思(哪里b是 aBa是一个A)?

对于前两种情况,可能的答案是a1.isEqualTo(a2)当且仅当a1 == a2b1.isEqualTo(b2)当且仅当b1 == b2

对于后两种情况,我们必须决定是否有办法让 aA等于 a B。最简单的解决方案(我认为)是 anA永远不能等于 a B

所以我们可以这样写一致性:

extension A: CustomEquatable {
    func isEqualTo(_ other: CustomEquatable) -> Bool {
        return (other as? A) == self
    }
}

extension B: CustomEquatable {
    func isEqualTo(_ other: CustomEquatable) -> Bool {
        return (other as? B) == self
    }
}

这两种一致性的唯一区别是强制转换类型(在右侧as?)。所以我们可以将一致性分解到一个协议扩展中,如下所示:

extension CustomEquatable where Self: Equatable {
    func isEqualTo(_ other: CustomEquatable) -> Bool {
        return (other as? Self) == self
    }
}

有了这个协议扩展,我们可以在不为每个协议实现的情况下制定AB遵守:CustomEquatableisEqualTo

extension A: CustomEquatable { }
extension B: CustomEquatable { }

要测试代码:

let a1 = A(name: "a1")
let a2 = A(name: "a2")
let b1 = B(id: 1)
let b2 = B(id: 2)

a1.isEqualTo(a1) // true
a1.isEqualTo(a2) // false
b1.isEqualTo(b1) // true
b1.isEqualTo(b2) // false
a1.isEqualTo(b1) // false
b1.isEqualTo(a1) // false

推荐阅读