是否可以将Swift泛型类函数返回类型限制为同一个类或子类?

时间:2014-12-06 21:14:18

标签: inheritance swift polymorphism generics

我在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,但sciCalculator,并且调用sci.showKind()会返回&#34;常规&#34;。

有没有办法使用泛型来实现所需的结果,还是一个bug?

4 个答案:

答案 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)

结果是一样的。

更有趣的观察结果:sciScientificCalculator类型的变量,但它指向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"