una trabajo significa saber que genericas función funciones funcion ejemplos diferenciable definicion cómo clase inheritance swift polymorphism generics

inheritance - trabajo - ¿Es posible restringir el tipo de devolución de la función de clase genérica Swift a la misma clase o subclase?



que significa de clase c1 (4)

Extiendo una clase base (una que no controlo) en Swift. Deseo proporcionar una función de clase para crear una instancia escrita a una subclase. Se requiere una función genérica. Sin embargo, una implementación como la siguiente no devuelve el tipo de subclase esperado.

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()

El depurador informa T como ScientificCalculator , pero sci es Calculator y llama a sci.showKind() devuelve "regular".

¿Hay alguna manera de lograr el resultado deseado usando genéricos, o es un error?


Actualización, utilicé la calculadora como tipo de devolución que no tiene sentido. Debe ser uno mismo, pero aún así debe existir un init requerido:

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()

Además de Sean Woodward, funcionará si las calculadoras tienen inicializadores (obligatorios). Anular eso en una subclase no es necesario.

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


De acuerdo, desde los foros de desarrolladores , si tienes el control de la clase base, es posible que puedas implementar el siguiente trabajo.

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()

Desafortunadamente, si no tienes el control de la clase base, este enfoque no es posible.


Esto no explica por qué su enfoque genérico no está funcionando. Solo estoy buscando una alternativa.

Parece que con Swift han reemplazado los métodos de fábrica con los inicializadores de conveniencia. Puede crear un nuevo inicializador de conveniencia y agregarlo con una extensión a 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"


Hay un error en alguna parte, quiero decir, no en tu código :)

Este es obviamente un método genérico:

class func create<T:Calculator>() -> T

T se deduce por el tipo de variable al que se asigna el valor de retorno, que en su caso es ScientificCalculator .

Un caso más interesante. Modifiquemos la función create modo que el tipo de T se haga explícito, independientemente del tipo de la variable a la que se asigna la instancia:

class func create<T:Calculator>(type: T.Type) -> T let sci: ScientificCalculator = ScientificCalculator.create(ScientificCalculator.self)

El resultado es el mismo.

Una observación más interesante: sci es una variable del tipo ScientificCalculator , pero apunta a una instancia de Calculator . Entonces este código:

sci.model

compila, pero genera una excepción de tiempo de ejecución porque no hay una propiedad de model definida en la clase base.

Esto es claramente un error del compilador: una instancia de una superclase se asigna a una variable cuyo tipo es una de sus subclases; eso nunca debería ser posible (aunque lo contrario es posible)

Lea también mi respuesta a una pregunta similar