无法将类型'child'的返回表达式转换为返回类型T
我在Swift中使用泛型挣扎了一下。无法将类型'child'的返回表达式转换为返回类型T
我有以下代码:
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 classtype写出构造函数。 (它在真实课程中有很多参数,我喜欢保持它的清洁)。
我得到的错误是: 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
一个实例 - 这已经filed as a bug 。
要解决这一点,你就必须做一些力铸造两轮牛车:
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
的方法(比较Return instancetype in Swift )。在这种情况下施加的力总是会成功,因为super.clone()
将始终返回Self
实例,因此在此方法中必须是Child
。
有趣。如果它不适用于需要forceCast的bug,我会使用它。但目前它看起来更丑陋,只是返回克隆! T'。希望这得到修复!现在我会接受,因为它看起来像是正确的方式,它可以承受的错误。 – Peterdk
@Peterdk做'as的问题!你原来的代码中的T''可以在实例不能转换为'T'时崩溃。考虑一下,如果你有'class Foo:Parent {}',然后有一个叫做'child'的'Child'的实例。做'让foo:Foo = child.clone()'会崩溃,因为'Child'的一个实例不能转换为'Foo'。使用返回类型'Self'的好处是编译器知道对于一个'Child'实例,调用'clone()'将返回一个'Child'实例。这只是一个耻辱,它目前不知道这是什么时候调用它'超':/ – Hamish
好吧,这种情况不会发生在我的情况。我同意使用Self是一个更好的选择,但不喜欢我需要编码的额外篮球。 – Peterdk
你应该考虑使用值类型('struct')。值类型在赋值时被复制,因此您不必手动执行。你将失去继承的能力,但你可以使用协议和扩展来解决这个问题。 – Palle
谢谢,但我不能使用结构,因为类也需要在Objective-C中使用。 – Peterdk
如果你的类是一个NSObject子类,你可以使用[NSCopying](https://developer.apple.com/reference/foundation/nscopying)。 – Palle