我有一个A类,它符合Equatable协议,实现了==函数.在B子类中,我用更多的判断覆盖==.

然而,当我在B的两个实例数组(都有Array<A>类型)之间进行比较时,会调用A==.当然,如果我将两个数组的类型都更改为Array<B>,则会调用== for B.

我想出了以下解决方案:

A.swift:

internal func ==(lhs: A, rhs: A) -> Bool {
    if lhs is B && rhs is B {
        return lhs as! B == rhs as! B
    }
    return ...
}

这看起来很难看,必须对A的每个子类进行扩展.有没有办法确保先调用== for subclass?

推荐答案

对于包含BArray<A>调用等于A的原因是,自由函数的重载是静态解决的,而不是动态解决的——也就是说,在编译时基于类型,而不是在运行时基于指向的值.

这并不奇怪,因为==没有在类内声明,然后在子类中重写.这似乎非常有限,但老实说,使用传统的OO技术定义多态性平等是极其困难的(而且是虚假的).更多信息请参见this linkthis paper.

天真的解决方案可能是在A中定义一个动态调度函数,然后定义==来调用:

class A: Equatable {
    func equalTo(rhs: A) -> Bool {
        // whatever equality means for two As
    }
}

func ==(lhs: A, rhs: A) -> Bool {
    return lhs.equalTo(rhs)
}

然后,当你实现B时,你会覆盖equalTo:

class B: A {
    override func equalTo(rhs: A) -> Bool {
        return (rhs as? B).map { b in
            return // whatever it means for two Bs to be equal
        } ?? false   // false, assuming a B and an A can’t be Equal
    }
}

你仍然需要跳as?支舞,因为你需要确定右边的参数是否是B(如果equalTo直接取B,那就不是合法的覆盖).

这里还隐藏着一些可能令人惊讶的行为:

let x: [A] = [B()]
let y: [A] = [A()]

// this runs B’s equalTo
x == y
// this runs A’s equalTo
y == x

也就是说,参数的顺序会改变行为.这并不好——人们期望平等是对称的.所以你真的需要上面链接中描述的一些技术来正确解决这个问题.

在这一点上,你可能会觉得这一切都变得有点不必要了.很可能是这样,特别是考虑到Swift标准库中Equatable的文档中的以下注释:

Equality implies substitutability.当x == yxy

三重等于===的类实例标识是

考虑到这一点,如果你实现平等的方式是not,你可能会很高兴两个相等的值被彼此替换,那么你可能会认真地重新考虑对你的Equatable实现产生兴趣.避免这种情况的一种方法是将对象标识看作是平等的度量,并用===来实现==,这只需要对超类进行一次.或者,您可以问自己,是否需要实现继承?如果不是,考虑放弃它并使用值类型,然后使用协议和泛型来捕获您正在寻找的多态行为.

Swift相关问答推荐

使用简单变量和函数的奇怪行为

TabView中的视频播放器意外播放

在Swift中,是否只有iOS版本超过15才能导入Swift包?

如何在visionOS中定制悬停效果区域

同时具有每个文本的标识符的文本组的可扩展性标识符

如何异步返回视图?什么?

从任务中打印

如何在 Vapor 中制作可选的查询过滤器

使 tabview 垂直将视图移动到右侧 swift ui

如何绑定环境变量ios17

将弱引用作为类函数引用传递时,弱引用无法按预期工作

确定路径是否相交的有效方法

如何避免从模块导入函数

为什么 SwiftUI 不在工具栏菜单中反映 @State 属性值?

判断 Swift 程序是否正在输出到终端

如何有条件地格式化 SwiftUI 代码

NSFontAttributeName 已更改为 String

如何从 UITableViewCell 类中引用 UITableViewController?

如何使用 Swift 枚举作为字典键? (符合 Equatable)

如何判断 firebase 数据库值是否存在?