我在 Swift 中的泛型方面有点挣扎。
我有以下代码:
class Parent {
init(value: SomeThing) {
// ...
}
func clone<T: Parent>() -> T {
return T(value: SomeThing)
}
}
class Child : Parent {
var otherValue: SomeThingElse?
override func clone<T>() -> T where T : Parent {
let clone: Child = super.clone()
clone.otherValue = self.otherValue
return clone //ERROR: cannot convert return expression of type 'Child' to return type T
}
}
这个想法是创建一个简单的方法,该方法返回具有相同值的子实例的新副本。 我不想为每个 Child 类类型写出构造函数。(它在真正的类中有很多参数,我喜欢保持干净)。
我得到的错误是:cannot convert return expression of type 'Child' to return type T
建议的解决方案是使其return clone as! T
。但这样我就失去了使用泛型类的理由。
知道如何在保持通用而不是在每个类中写出构造函数的同时解决这个问题吗?
您需要具有返回类型Self
,而不是使用约束为Parent
的泛型占位符。使用泛型占位符,您说clone()
可以返回从Parent
继承的任何特定具体类型的实例。然而,事实并非如此 – 您只想返回与接收方类型相同的实例,这就是Self
表达的内容。
然后,您还需要实现一个required
初始化器,以便它可以调用所有子类,从而允许对它们调用clone()
,而不必覆盖它们。
struct Something {}
struct SomethingElse {}
class Parent {
var something: Something
required init(something: Something) {
self.something = something
}
func clone() -> Self {
// call the initialiser on the dynamic metatype of the instance,
// ensuring that we're instantiating a Self instance.
return type(of: self).init(something: something)
}
}
然后,Child
的实现应该像这样简单:
class Child : Parent {
var somethingElse: SomethingElse?
override func clone() -> Self {
let clone = super.clone()
clone.somethingElse = somethingElse
return clone
}
}
然而,不幸的是,在super
上调用clone()
会返回一个静态类型为Parent
而不是Self
的实例——这已被归档为错误。
要解决此问题,您必须执行一些强制投射黑客操作:
override func clone() -> Self {
let clone = super.clone() as! Child
clone.somethingElse = somethingElse
func forceCast<T>(_ value: Child) -> T { return value as! T }
return forceCast(clone)
}
嵌套forceCast(_:)
函数用于解决我们目前无法在方法中直接转换为Self
的事实(比较 Swift 中的 Return 实例类型)。在这种情况下,两个强制强制转换将始终成功,因为super.clone()
将始终返回一个Self
实例,因此该方法中必须是一个Child
。