我创建了一个类,用作"抽象类" (仅用于子类,不直接实例化)。由于Swift不支持这一点,因此必须使用例如抽象方法体中的fatalError。
我的抽象类必须是等同的。所以我想,我在equals方法中使用fatalError:
class MySuperClass:Equatable {
}
func ==(lhs: MySuperClass, rhs: MySuperClass) -> Bool {
fatalError("Must override")
}
class MySubClass:MySuperClass {
let id:Int
init(_ id:Int) {
self.id = id
}
}
func ==(lhs: MySubClass, rhs: MySubClass) -> Bool {
return lhs.id == rhs.id
}
let a = MySubClass(1)
let b = MySubClass(2)
let c = MySubClass(2)
a == b
b == c
这很有效。虽然我的子类有一个类型参数,但我有一个小问题。现在示例如下所示:
class MySuperClass:Equatable {
}
func ==(lhs: MySuperClass, rhs: MySuperClass) -> Bool {
fatalError("Must override")
}
class MySubClass<T>:MySuperClass {
let id:Int
init(_ id:Int) {
self.id = id
}
}
func ==<T>(lhs: MySubClass<T>, rhs: MySubClass<T>) -> Bool {
return lhs.id == rhs.id
}
let a = MySubClass<Any>(1)
let b = MySubClass<Any>(2)
let c = MySubClass<Any>(2)
a == b
b == c
现在它崩溃了,因为它没有&#34;看到&#34;重写等于,它只在超类中执行等号。
我知道Swift在使用泛型类型的覆盖方面存在一些问题。我想虽然这仅限于与obj-c的互动。这看起来至少像语言缺陷或错误,如果B是A的子类,为什么泛型B的等于不覆盖A类的等于?
答案 0 :(得分:1)
在重载分辨率中,非泛型函数总是优先于泛型函数,因此不考虑将采用子类的函数放在超类之前的较小规则。
一种可能的解决方案是使超类==
也是通用的。这样,两个泛型函数之间的选择规则就开始了,在这种情况下,更具体的一个是采用由T参数化的特定类的那个:
func ==<T: MySuperClass>(lhs: T, rhs: T) -> Bool {
// bear in mind, this is a question of compile-time overloading,
// rather than overriding
fatalError("Must override")
}
func ==<T>(lhs: MySubClass<T>, rhs: MySubClass<T>) -> Bool {
return lhs.id == rhs.id
}
let a = MySubClass<Any>(1)
let b = MySubClass<Any>(2)
let c = MySubClass<Any>(2)
// no longer asserts
a == b
b == c
答案 1 :(得分:1)
正如Airspeed所说,问题在于运算符的实现不是类/结构实现的一部分=&gt;因此,继承在那里不起作用。
您可以做的是保持类实现中的逻辑并让运算符使用它。例如。以下将满足您的需求:
class MySuperClass: Equatable {
func isEqualTo(anotherSuperClass: MySuperClass) -> Bool {
fatalError("Must override")
}
}
func == (lhs: MySuperClass, rhs: MySuperClass) -> Bool {
return lhs.isEqualTo(rhs)
}
class MySubClass<T>:MySuperClass {
let id: Int
init(_ id: Int) {
self.id = id
}
override func isEqualTo(anotherSuperClass: MySuperClass) -> Bool {
if let anotherSubClass = anotherSuperClass as? MySubClass<T> {
return self.id == anotherSubClass.id
}
return super.isEqualTo(anotherSuperClass) // Updated after AirSpeed remark
}
}
let a = MySubClass<Any>(1)
let b = MySubClass<Any>(2)
let c = MySubClass<Any>(2)
a == b
b == c
...正如您所看到的那样==
运算符只定义了一次,它使用MySuperClass
的方法来确定它的两个参数是否相等。之后.isEqualTo()
处理剩下的事情,包括在MySubClass
级别使用继承机制。
<强> UPD 强>
上述方法的好处是以下方法仍然有效:
let a2: MySuperClass = a
let b2: MySuperClass = b
let c2: MySuperClass = c
a2 == b2
b2 == c2
...即,无论编译时的变量类型如何,行为都将由实际的实例类型决定。