我在Swift中扩展了一个基类(我无法控制的基类)。我想提供一个类函数来创建一个类型为子类的实例。通用功能是必需的。但是,类似下面的实现不会返回预期的子类类型。
class Calculator {
func showKind() { println("regular") }
}
class ScientificCalculator: Calculator {
let model: String = "HP-15C"
override func showKind() { println("scientific") }
}
extension Calculator {
class func create<T:Calculator>() -> T {
let instance = T()
return instance
}
}
let sci: ScientificCalculator = ScientificCalculator.create()
sci.showKind()
调试器将T
报告为ScientificCalculator
,但sci
为Calculator
,并且调用sci.showKind()
会返回&#34;常规&#34;。
有没有办法使用泛型来实现所需的结果,还是一个bug?
答案 0 :(得分:8)
好的,从developer forums开始,如果你掌握了基类,你就可以实现以下解决方法。
class Calculator {
func showKind() { println("regular") }
required init() {}
}
class ScientificCalculator: Calculator {
let model: String = "HP-15C"
override func showKind() { println("\(model) - Scientific") }
required init() {
super.init()
}
}
extension Calculator {
class func create<T:Calculator>() -> T {
let klass: T.Type = T.self
return klass()
}
}
let sci:ScientificCalculator = ScientificCalculator.create()
sci.showKind()
不幸的是,如果您无法控制基类,则无法使用此方法。
答案 1 :(得分:2)
某处有一个错误 - 我的意思是,不在您的代码中:)
这显然是一种通用方法:
class func create<T:Calculator>() -> T
T
由返回值所分配的变量类型推断,在您的情况下为ScientificCalculator
。
一个更有趣的案例。让我们修改create
函数,使T
的类型显式化,而不管实例分配给的变量类型如何:
class func create<T:Calculator>(type: T.Type) -> T
let sci: ScientificCalculator = ScientificCalculator.create(ScientificCalculator.self)
结果是一样的。
更有趣的观察结果:sci
是ScientificCalculator
类型的变量,但它指向Calculator
的实例。所以这段代码:
sci.model
编译,但会生成运行时异常 - 因为基类中没有定义model
属性。
这显然是一个编译器错误:超类的一个实例被分配给一个类型是其子类之一的变量 - 这是永远不可能的(尽管可能相反)
另请阅读我对similar question
的回答答案 2 :(得分:1)
更新,我使用计算器作为返回类型,没有任何意义。它应该是Self,但仍然必须存在必需的init:
class Calculator {
func showKind() { println("regular") }
required init() {
}
}
class ScientificCalculator: Calculator {
let model: String = "HP-15C"
override func showKind() { println("scientific") }
}
extension Calculator {
class func create() -> Self {
return self()
}
}
var b = ScientificCalculator.create() // HP-15C
b.showKind()
除了Sean Woodward之外,如果计算器具有(必需的)初始化器,它将起作用。不需要在子类中覆盖它。
class Calculator {
required init() {
}
func showKind() { println("regular") }
}
class ScientificCalculator: Calculator {
let model: String = "HP-15C"
override func showKind() { println("scientific") }
}
extension Calculator {
class func create<T:Calculator>( type:T.Type ) -> T {
return type() as T
}
class func newInstance() -> Calculator {
return self()
}
}
var b = ScientificCalculator.newInstance() // HP-15C
b.showKind() // sientific
答案 3 :(得分:0)
这并不能解释为什么您的通用方法不起作用。我只是在寻找替代方案。
Swift似乎已经用便利初始化器替换了工厂方法。您可以创建一个新的便利初始值设定项,并将其添加到Calculator
的扩展名。
extension Calculator {
convenience init(name: String) {
println(name)
self.init()
}
}
let reg = Calculator(name: "Reg")
reg.showKind() // "regular"
let sci = ScientificCalculator(name: "Sci")
sci.showKind() // "scientific"