You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift Equatable子类!=调用父类==实现的原因

问题复现

原有代码实现:

class Base: Equatable {
    static func == (lhs: Base, rhs: Base) -> Bool {
        lhs.id == rhs.id
    }
    let id: String
    init(id: String) {
        self.id = id
    }
}

class SubClass: Base {
    public var id2: String?
    public init(id1: String, id2: String? = nil) {
        self.id2 = id2
        super.init(id: id1)
    }
    static func == (lhs: SubClass, rhs: SubClass) -> Bool {
        lhs.id2 == rhs.id2 && lhs.id == rhs.id
    }
}

测试代码与异常表现:

// a、b均为SubClass类型的实例
print(a != b) // 输出false,实际调用Base类的==实现
print(a == b) // 输出false,实际调用SubClass类的==实现

相同类型的两个实例,调用==和!=时走了不同层级的相等判断逻辑,不符合预期。

问题原因
  • Swift中!=不需要遵守Equatable的类型单独实现,标准库提供了全局泛型默认实现:static func != <T: Equatable>(lhs: T, rhs: T) -> Bool { return !(lhs == rhs) },这个实现走静态调度,不会动态识别子类的重载方法。
  • 子类中实现的==(lhs: SubClass, rhs: SubClass)是方法重载而非方法重写:基类==的入参类型为Base,子类同名方法入参为SubClass,没有标注override,不会被纳入基类的动态派发列表。
  • 调用==时,若变量声明类型为SubClass,编译器可静态匹配到子类的重载版本;调用!=时,编译器直接绑定标准库的泛型实现,该实现基于Base类型的Equatable 协议遵循关系静态调用基类==,不会触发子类的重载逻辑。
修复方案

将相等判断逻辑改为支持动态派发的实例方法,基类的==统一调用该实例方法,子类重写实例方法即可实现全运算符的一致调度:

class Base: Equatable {
    static func == (lhs: Base, rhs: Base) -> Bool {
        lhs.isEqual(to: rhs)
    }
    
    let id: String
    init(id: String) {
        self.id = id
    }
    
    /// 可被子类重写的相等判断入口,支持动态派发
    func isEqual(to other: Base) -> Bool {
        return self.id == other.id
    }
}

class SubClass: Base {
    public var id2: String?
    public init(id1: String, id2: String? = nil) {
        self.id2 = id2
        super.init(id: id1)
    }
    
    override func isEqual(to other: Base) -> Bool {
        guard let otherSub = other as? SubClass else {
            return false
        }
        return self.id == otherSub.id && self.id2 == otherSub.id2
    }
}

修复后无论调用==还是!=,都会通过动态派发到实际类型对应的isEqual实现,不会出现调度不一致的问题,子类也不需要单独编写static func ==的重载逻辑。


内容的提问来源于stack exchange,提问作者Johnny

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 23:33:26