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

sea*_*ard 5 generics polymorphism inheritance swift

我在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()
Run Code Online (Sandbox Code Playgroud)

调试器报告TScientificCalculator,但是sciCalculator和调用sci.showKind()返回"常规".

有没有办法使用泛型达到预期的结果,还是一个bug?

sea*_*ard 8

好的,从开发人员论坛,如果您可以控制基类,您可能能够实现以下解决方案.

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()
Run Code Online (Sandbox Code Playgroud)

不幸的是,如果您无法控制基类,则无法使用此方法.


Ant*_*nio 2

某个地方有一个错误 - 我的意思是,不是在你的代码中:)

这显然是一个通用方法:

class func create<T:Calculator>() -> T
Run Code Online (Sandbox Code Playgroud)

T由返回值分配给的变量的类型推断,在您的情况下是ScientificCalculator.

一个更有趣的案例。让我们修改该create函数,使 的类型T变得显式,而不管实例分配给的变量的类型如何:

class func create<T:Calculator>(type: T.Type) -> T

let sci: ScientificCalculator = ScientificCalculator.create(ScientificCalculator.self)
Run Code Online (Sandbox Code Playgroud)

结果是一样的。

一个更有趣的观察:sci是一个类型变量ScientificCalculator,但它指向 的一个实例Calculator。所以这段代码:

sci.model
Run Code Online (Sandbox Code Playgroud)

model编译,但生成运行时异常 - 因为基类中没有定义属性。

这显然是一个编译器错误:超类的实例被分配给其类型为其子类之一的变量 - 这永远不可能(尽管相反的情况也是可能的)

另请阅读我对类似问题的回答