我有一个类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子类?
A
为Array<A>
包含一个的调用相等性的原因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
如果您实现平等的方式不是让两个相等的值相互替代而感到满意,那么您可能会很想重新考虑自己的实现。避免这种情况的一种方法是将对象标识视为相等性的度量,并==
根据===
进行实现,对于超类仅需要执行一次。另外,您可能会问自己,您真的需要实现继承吗?如果不是,请考虑放弃它,而使用值类型,然后使用协议和泛型来捕获您要查找的多态行为。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句