当前位置: 首页 > 面试题库 >

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

吕骞尧
2023-03-14
问题内容

我有一个类A,它符合Equatable协议并实现了==功能。在子类中,B我将==进行更多检查。

但是,当我在两个实例数组B(都具有类型Array<A>)之间进行比较时,会调用==for
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子类?


问题答案:

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

鉴于==没有在类内部声明然后在子类中重写,这不足为奇。这看似非常有限,但说实话,使用传统的OO技术定义多态相等性非常困难(并且在欺骗上)。有关更多信息,请参见此链接和本文。

天真的解决方案可能是在中定义动态分派的函数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

即,参数的顺序改变了行为。这不好-人们期望平等是对称的。因此,实际上您需要上面链接中描述的一些技术才能正确解决此问题。

在这一点上,您可能会觉得所有这些都变得不必要了。可能是这样,尤其是考虑Equatable到Swift标准库文档中的以下注释:

平等意味着可替代性 。当和 时x == y, 在仅取决于其值的任何代码中均可互换。x``y

用三等号区分的类实例标识=== 显然不是实例值的一部分。暴露的其他非增值环节Equatable的类型是气馁,任何
暴露应该被文件明确指出。

鉴于此,Equatable如果您实现平等的方式 不是
让两个相等的值相互替代而感到满意,那么您可能会很想重新考虑自己的实现。避免这种情况的一种方法是将对象标识视为相等性的度量,并==根据===进行实现,对于超类仅需要执行一次。另外,您可能会问自己,您
真的 需要实现继承吗?如果没有,请考虑放弃它,而使用值类型,然后使用协议和泛型来捕获您要查找的多态行为。



 类似资料:
  • 问题内容: 在Swift中,有人可以解释如何用原始属性的子类覆盖另一个超类的属性吗? 举一个简单的例子: 这给出了错误: 如果我将机箱设为“ var”,则会收到错误消息: 在指南中“覆盖属性”下唯一可以找到的内容表明,我们必须覆盖getter和setter,这可能会更改属性的值(如果它是’var’),但是如何更改属性类呢? ? 问题答案: Swift不允许您更改任何变量或属性的类类型。相反,您可以

  • 问题内容: 是否有一种标准方法可以在Swift中制作“纯虚函数”,即。一个 必须 由每个子类中被覆盖,并且,如果不是的话,将导致编译时错误? 问题答案: 您有两种选择: 将超类定义为协议而不是类 Pro :编译时检查每个“子类”(不是实际的子类)是否实现了所需的方法 缺点 :“超类”(协议)无法实现方法或属性 2.声明该方法的超级版本 例: Pro :可以在超类中实现方法和属性 缺点 :不检查编译

  • 问题内容: 关于如何考虑 超字段的 子类中的 Override &in,是否有特定规则?知道有很多参数:超字段是private / public,有/没有getter … 例如,Netbeans生成的equals()和hashCode()不会考虑超级字段…和 将返回true :( 如果要查看Netbeans生成的equals()和hashCode(): 问题答案: 儿童不应该检查父母的私人成员 但

  • 我有一个基类,它定义了类方法,用于返回用于构建服务url的各种信息。基类还定义了一个用于构建该url的实例方法。我希望基类有这个方法的默认实现,这样当我需要url不同时,我只需要在子类中重写它。我如何让这个基方法调用重写的类方法来使用子类中的类方法构建url?下面是我现在的代码,但它不起作用: 基类方法: op ationId、operationVersion和方法类型是在子类中实现的类方法,但是

  • 这是一个更大的项目,所以我将简化结构,不包括这里涉及的所有代码,但我想知道这在概念上是否可行,以及我可能遇到的潜在障碍。 我从主类中得到了几个级别的子类,其中一个级别包含方法age()(从顶部超类重写),该方法调用useEnergy()。此类的直接子类重写age()。该类的直接子类需要重写useEnergy(),但被重写方法中的代码永远不会执行(通过System.out.printlns验证)。有

  • 问题内容: 我想在超类中实现,并通过在运行时在超类中的特定子类上调用类方法在所有子类中使用它。 MySuperClass 子类是否有可能在运行时访问类函数? 问题答案: 我想我明白了你的意思。您创建一个类,实现一个初始化程序和一个类(静态)函数: 接下来,您要创建子类,并让初始化程序调用该方法的重写版本。您只需要重写该方法即可: 现在,当您创建的实例时,显示的内容是: 这是预期的输出。 请注意,初