这里,layEgg()想要重用chickenFactory(Chicken.Type)。问题是layEgg返回Self?所以我得到了这个类型的实例或者没有。
但是,chickenFactory返回一个Chicken,需要将其转换为我的任何类型。
enum BiologicalGender : String {
case male = "male"
case female = "female"
}
class Chicken {
let gender : BiologicalGender
required init (_ gender : BiologicalGender) {
self.gender = gender
}
class func chickenFactory(_ chickenType : Chicken.Type) -> Chicken {
if (arc4random_uniform(2) == 0) {
return chickenType.init(.male)
} else {
return chickenType.init(.female)
}
}
func layEgg() -> Self? {
if (self.gender == .female) {
return Chicken.chickenFactory(type(of:self)) // need a cast here
} else {
return nil
}
}
}
如何进行多态转换?
答案 0 :(得分:4)
问题在于chickenFactory(_:)
表示它采用类型Chicken.Type
作为参数并输出Chicken
的实例。输出的实例不必是您传入的类型(例如,当您输入Chicken
类型时,它可以输出ChickenSubclass.self
的实例。
您想要的不是类型转换,而是说输出的实例与您输入的类型的相同类型。为了表达这一点,您可以使用通用占位符:
class func chickenFactory<T : Chicken>(_ chickenType : T.Type) -> T {
if (arc4random_uniform(2) == 0) {
return chickenType.init(.male)
} else {
return chickenType.init(.female)
}
}
现在
func layEgg() -> Self? {
if (self.gender == .female) {
return Chicken.chickenFactory(type(of: self))
} else {
return nil
}
}
编译得很好,因为编译器知道可以从返回type(of: self)
的函数返回类型Self?
的实例。
尽管如此,chickenFactory(_:)
的类型参数似乎是多余的,您可以通过在静态范围内使用self
来使用它所调用的类型:
class func chickenFactory() -> Self {
if (arc4random_uniform(2) == 0) {
return self.init(.male)
} else {
return self.init(.female)
}
}
func layEgg() -> Self? {
if (self.gender == .female) {
return type(of: self).chickenFactory()
} else {
return nil
}
}
答案 1 :(得分:1)
问题的另一个解决方案是这个。查看this answer
func layEgg() -> Self? {
if (self.gender == .female) {
return makeEgg()
} else {
return nil
}
}
func makeEgg<T>()->T?{
return Chicken.chickenFactory(type(of:self)) as? T
}
答案 2 :(得分:0)
这不一定会改进代码,但是这里有一个包含原始工厂的类函数,可以完成对很多人演示的自我投射。
还包括原始的,改进的通用chickenFactory()。
class Chicken {
let gender : BiologicalGender
required init (_ gender : BiologicalGender) {
self.gender = gender
}
class func chickenFactory<T:Chicken>(_ chickenType : T.Type) -> T {
if (arc4random_uniform(2) == 0) {
return chickenType.init(.male)
} else {
return chickenType.init(.female)
}
}
class func poorlyTypedChickenFactory(_ chickenType : Chicken.Type) -> Chicken {
if (arc4random_uniform(2) == 0) {
return chickenType.init(.male)
} else {
return chickenType.init(.female)
}
}
private class func chickenFromPoorlyTypedFactory<T>(_ chickenType : Chicken.Type) -> T?
{
let chicken = poorlyTypedChickenFactory(chickenType) as? T
return chicken
}
func layEgg() -> Self? {
if (self.gender == .female) {
return Chicken.chickenFromPoorlyTypedFactory(type(of:self))
} else {
return nil
}
}
}