Swift:覆盖子类中的==仅在超类中调用==

前端之家收集整理的这篇文章主要介绍了Swift:覆盖子类中的==仅在超类中调用==前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个类A,它符合Equatable协议并实现== function。在子类B中,我使用更多检查覆盖==。

但是,当我在B的两个实例数组(两者都具有类型Array< A>)之间进行比较时,调用A = A。当然,如果我将两个数组的类型更改为Array< B>,则调用B来调用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的每个子类进行扩展。有没有办法确保首先调用子类的==?

为数组< A>调用A的相等性的原因包含B的是自由函数的重载是静态解决的,而不是动态解析的 – 也就是说,在编译时基于类型,而不是在运行时基于指向的值。

这并不奇怪,因为==未在类中声明,然后在子类中重写。这似乎是非常有限的,但老实说,使用传统的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
    }
}

你还需要做一个吗?跳舞,因为你需要确定右手参数是否是B(如果等于直接取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. When x == y,x and y
are interchangeable in any code that only depends on their values.

Class instance identity as distinguished by triple-equals === is
notably not part of an instance’s value. Exposing other non-value
aspects of Equatable types is discouraged,and any that are
exposed should be explicitly pointed out in documentation.

鉴于此,你可能真的想重新考虑使用你的Equatable实现,如果你实现相等的方式不是你对两个相等的值相互替换感到满意的方式。避免这种情况的一种方法是将对象标识视为相等的度量,并根据===实现==,这对于超类只需要执行一次。或者,你可以问自己,你真的需要实现继承吗?如果没有,请考虑抛弃它并使用值类型,然后使用协议和泛型来捕获您正在寻找的多态行为。

猜你在找的Swift相关文章