Generics in Swift – "Parámetro genérico 'T' no se pudo inferir

Me gustaría devolver un UIViewController conforme a MyProtocol desde un método, así que estoy usando la firma del método:

 func myMethod<T where T : UIViewController, T : MyProtocol>() -> T { 

Lo primero que no entiendo: si myMethod devuelve, por ejemplo, un MyViewController que tiene que seguir la firma, debo MyViewController que lo MyViewController :

 class MyViewController: UIViewController, MyProtocol 

No puedo simplemente return MyViewController() pero tengo que return MyViewController() as! T esta manera: ¡ return MyViewController() as! T return MyViewController() as! T : ¿por qué es necesario?

Y la segunda cosa: ¿cómo puedo usar este método en alguna parte? No puedo simplemente decir

 let x = myMethod() as? UIViewController 

como recibo el error

 Generic parameter 'T' could not be infernetworking 

¿Cómo puedo lograr algo como esto? Si lo MyViewController a MyViewController funciona, pero me gustaría evitar eso, por supuesto.

EDITAR: Ejemplo

 class MyViewController : UIViewController, MyProtocol { } protocol MyProtocol { } func myMethod<T>() -> T where T : UIViewController, T : MyProtocol { return MyViewController() as! T // why is the cast necessary? } 

ok, obtengo una parte, pero ¿por qué es necesario el elenco para T ? MyViewController es una subclass de UIViewController y se ajusta al protocolo, por lo que no debe ser necesario el yeso, ¿verdad?

 func myMethod<T where T : UIViewController, T : MyProtocol>() -> T 

Esta statement dice: Existe una function llamada myMethod , tal que myMethod devuelve una T específica donde T es un subtipo de UIViewController y también MyProtocol . Esto no dice qué tipo de T es realmente, y no dice que solo haya uno de tales myMethod . Puede haber muchos si hay muchos types que son ambas subclasss de UIViewController y se ajustan a MyProtocol . Cada uno de esos types crea una nueva versión de myMethod (realmente una nueva solución a la afirmación de myMethod , que existe tal function).

Esto no es lo mismo que:

 func myMethod() -> UIViewController 

Eso dice: La function myMethod devuelve cualquier subtipo de UIViewController .

No hay forma en Swift de express "cualquier tipo que sea una subclass de UIViewController y es un subtipo de MyProtocol". Solo puede discutir un tipo específico que cumpla con ese criterio. Swift no puede combinar classs y protocolos de esta manera; Es solo una limitación actual del lenguaje, no un problema de layout profundo.

El específico frente a cualquiera es el problema. Hay muchas funciones que satisfacen su statement myMethod . Cada T que pueda conectar que cumpla con las reglas sería un candidato. Entonces, cuando dices myMethod() , el comstackdor no sabe a qué T específico te refieres.

(Iba a expandir esta respuesta para proporcionarla en less teoría de types, más términos de "cómo lo haces en código", pero Donnywals ya tiene una excelente versión de eso).

* A su pregunta editada *

 func myMethod<T>() -> T where T : UIViewController, T : MyProtocol { return MyViewController() as! T // why is the cast necessary? } 

T es un tipo específico decidido por la persona que llama. No es "cualquier tipo que se ajuste", es "algún tipo específico y concreto que se ajuste". Considera el caso que llamaste:

 let vc: SomeOtherViewController = myMethod() 

En este caso, T es SomeOtherViewController . MyViewController no es ese tipo, así que ¿qué estás haciendo con el as! El reparto es peligroso.

En un método como este, devolver T significa que tienes que devolver T Si devuelve MyViewController , el tipo de devolución debe ser MyViewController . T es un tipo genérico que tomará la forma de lo que sea que el comstackdor Swift pueda inferir que es.

Entonces, con la firma de su método, una implementación simple del protocolo y el método podría verse así.

 protocol MyProtocol { var name: String { get set } } func myMethod<T where T : UIViewController, T : MyProtocol>() -> T { var vc = T() vc.name = "Hello, world" return vc } 

Entonces, considerando su ejemplo de uso:

 let x = myMethod() 

¿Cómo sabría el comstackdor cuál es el tipo concreto de T ? No hay nada que dé una pista de MyViewController . Lo único que sabemos es que cualquiera que sea T , debería ser MyViewController o una subclass de él. Y debe cumplir con MyProtocol . Pero esto no proporciona información sobre cuál debería ser el tipo de T

El único lugar donde el comstackdor puede inferir lo que queremos que T sea ​​es a través del valor de retorno. Todo el código entre <> son restricciones para lo que T está permitido. -> T es el único lugar donde T se ve fuera de las restricciones. Entonces, si de alguna manera podemos decirle al comstackdor lo que queremos que devuelva mi myMethod , le hemos dado suficiente información para inferir T

Tu tipografía funciona, pero estoy de acuerdo en que no es muy bonita. Una manera mucho más bonita para el comstackdor para inferir T es esto.

 let vc: MyViewController = myMethod() 

Al especificar el tipo de vc , el comstackdor entiende que queremos que myMethod devuelva un MyViewController . Entonces, ahora se puede inferir el tipo de T y si devolvemos T , en realidad devolvemos MyViewController .