Swift协议扩展,Self:Equatable无法正常工作

时间:2018-10-22 18:10:02

标签: swift generics swift-protocols

谁能阐明为什么这行不通?我收到错误消息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
    }
}

2 个答案:

答案 0 :(得分:2)

让我们从您的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)是什么意思(其中a1a2均为A类型)?
  • b1.isEqualTo(b2)是什么意思(其中b1b2均为B类型)?
  • a.isEqualTo(b)是什么意思(其中aA,而bB)?
  • b.isEqualTo(a)是什么意思(其中bB,而aA)?

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

对于后两种情况,我们必须确定A是否等于B的方法。我认为最简单的解决方案是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符合CustomEquatable,而无需为每个实现isEqualTo

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

答案 1 :(得分:1)

请从37:25开始观看WWDC 2015 Protocol-Oriented Programming in Swift

这几乎是从视频中摘录的。您必须将other有条件下调到Self
如果类型相同,则可以使用==,否则两个对象都不相等。

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