【问题标题】:Swift protocol extension where Self: Equatable doesn't workSelf: Equatable 不起作用的 Swift 协议扩展
【发布时间】:2018-10-23 02:46:35
【问题描述】:

谁能解释为什么这不起作用?我收到一个错误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
    }
}

【问题讨论】:

  • 问题在于,仅仅因为self 是等价的,而otherCustomEquatable(这意味着它也是Equatable),这并不意味着selfother 的类型相同。例如,如果IntString 都扩展为符合CustomEquatable,那么1.isEqualTo("a") 将调用1 == "a",它不会进行类型检查,因为== 要求LHS 和RHS 具有相同的类型.
  • 为了提供一个解决方案,我们需要知道你想用这个CustomEquatable 协议实现什么。这是您尝试解决可怕的“协议 'Equatable' 只能用作通用约束,因为它具有自身或相关类型要求”错误的尝试吗?
  • @Alexander 是的,是的,我是。
  • 这是AnyEquatable类型橡皮擦的正确实现:stackoverflow.com/a/46288607/3141234
  • @Alexander: "other is a CustomEquatable (这意味着它也是 Equatable)" – 除非我弄错了,other 可以是一个不同的 类型采用CustomEquatable,不必是Equatable。

标签: swift generics swift-protocols


【解决方案1】:

让我们从你的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) 是什么意思(其中aAbB)?
  • b.isEqualTo(a) 是什么意思(bBaA)?

对于前两种情况,可能的答案是a1.isEqualTo(a2) 当且仅当a1 == a2b1.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

【讨论】:

    【解决方案2】:

    请从 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
        }
    }
    

    【讨论】:

    • 谢谢,这确实很好地解释了它!
    猜你喜欢
    • 2017-04-24
    • 2015-12-09
    • 1970-01-01
    • 2017-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-02
    相关资源
    最近更新 更多