son qué metodos manejo instanciar genericos genericas datos con comparar clases arreglos generics swift protocols type-alias

generics - qué - Devolución de genéricos restringidos a partir de funciones y métodos



variables genericas (1)

Creo que la clave para entender qué está pasando aquí es distinguir entre cosas que se determinan dinámicamente en el tiempo de ejecución y cosas que se determinan estáticamente en el momento de la compilación. No ayuda que, en la mayoría de los lenguajes como Java, los protocolos (o interfaces) tengan que ver con el comportamiento polimórfico en tiempo de ejecución , mientras que en Swift, los protocolos con tipos asociados también se usan para obtener un comportamiento polimórfico en tiempo de compilación .

Cada vez que vea un marcador de posición genérico, como T en su ejemplo, qué tipo se rellena para esta T se determina en tiempo de compilación. Entonces, en tu ejemplo:

func returnsSomethingWithAwesomeness<T: HasAwesomeness>(key: String) -> T

está diciendo: returnsSomethingWithAwesomeness es una función que puede funcionar en cualquier tipo T , siempre que T ajuste a HasAwesomeness .

Pero lo que se completa para T se determina en el momento en que se llama returnsSomethingWithAwesomeness : Swift examinará toda la información en el sitio de llamadas y decidirá qué tipo es T , y reemplazará todos T marcadores de posición T con ese tipo. *

Por lo tanto, supongamos que en el sitio de llamada la elección es que T es una String , se puede pensar en returnsSomethingWithAwesomeness como reescrito con todas las apariciones del marcador de posición T reemplazado por String :

// giving the type of s here fixes T as a String let s: String = returnsSomethingWithAwesomeness("bar") func returnsSomethingWithAwesomeness(key: String) -> String { if key == "foo" { return "Amazing Foo" } else { return 42 } }

Tenga en cuenta que T se reemplaza con String y no con un tipo de HasAwesomeness . HasAwesomeness solo se usa como una restricción, es decir, restringe los posibles tipos T

Cuando lo miras así, puedes ver que ese return 42 en el else no tiene sentido, ¿cómo podrías devolver 42 desde una función que devuelve una cuerda?

Para asegurarse de que returnsSomethingWithAwesomeness pueda funcionar con cualquier T termine siendo, Swift lo restringe para que solo use aquellas funciones que están garantizadas para estar disponibles a partir de las restricciones dadas. En este caso, todo lo que sabemos sobre T es que se ajusta a HasAwesomeness . Esto significa que puede llamar al método returnsSomethingWithAwesomeness en cualquier T , o usarlo con otra función que constriñe un tipo a HasAwesomeness , o asignar una variable de tipo T a otra (todos los tipos soportan asignación), y eso es todo .

No se puede comparar con otros Ts (no hay garantía de que sea compatible == ). No puede construir nuevos (¿quién sabe si T tendrá un método de inicialización apropiado?). Y no puede crearlo a partir de un literal de cadena o entero (esto requeriría que T ajustara a StringLiteralConvertible o IntegerLiteralConvertible , lo que no necesariamente hace; de ​​ahí esos dos errores cuando intenta crear el tipo usando uno de estos tipos de literales).

Es posible escribir funciones genéricas que devuelven un tipo genérico que todo se ajusta a un protocolo. Pero lo que se devolvería sería un tipo específico, no el protocolo, por lo que el tipo no se determinaría de forma dinámica. Por ejemplo:

func returnCollectionContainingOne<C: ExtensibleCollectionType where C.Generator.Element == Int>() -> C { // this is allowed because the ExtensibleCollectionType procol // requires the type implement an init() that takes no parameters var result = C() // and it also defines an `append` function that allows you to do this: result.append(1) // note, the reason it was possible to give a "1" as the argument to // append was because of the "where C.Generator.Element == Int" part // of the generic placeholder constraint return result } // now you can use returnCollectionContainingOne with arrays: let a: [Int] = returnCollectionContainingOne() // or with ContiguousArrays: let b: ContiguousArray = returnCollectionContainingOne()

Piense en returnCollectionContainingOne en este código como si realmente fuera dos funciones, una implementada para ContiguousArray y otra para Array , escrita automáticamente por el compilador en el punto que usted las llama (y por lo tanto donde puede fijar C para que sea un tipo específico). No es una función que devuelve un protocolo, sino dos funciones que devuelven dos tipos diferentes. Así que de la misma manera que returnsSomethingWithAwesomeness no puede devolver un String o un Int en tiempo de ejecución en función de un argumento dinámico, no se puede escribir una versión de returnCollectionContainingOne que devuelva una matriz o una matriz contigua. Todo lo que puede devolver es una T , y en el momento de la compilación, cualquier cosa que T realmente sea puede ser completada por el compilador.

* esto es una ligera simplificación excesiva de lo que realmente hace el compilador, pero servirá para esta explicación.

Me gustaría crear una función que devuelva un objeto que se ajuste a un protocolo, pero el protocolo usa un tipo de typealias . Dado el siguiente ejemplo de juguete:

protocol HasAwesomeness { typealias ReturnType func hasAwesomeness() -> ReturnType } extension String: HasAwesomeness { func hasAwesomeness() -> String { return "Sure Does!" } } extension Int: HasAwesomeness { func hasAwesomeness() -> Bool { return false } }

String e Int se han ampliado para ajustarse a HasAwesomeness , y cada uno implementa el método hasAwesomeness() para devolver un tipo diferente.

Ahora me gustaría crear una clase que devuelva un objeto que se ajuste al protocolo HasAwesomeness . No me importa cuál es la clase, solo que puedo enviar el mensaje hasAwesomenss() . Cuando intento lo siguiente, genero un error de compilación:

class AmazingClass: NSObject { func returnsSomethingWithAwesomeness(key: String) -> HasAwesomeness { ... } }

ERROR: El protocolo ''HasAwesomeness'' solo se puede usar como restricción genérica porque tiene requisitos de tipo propio o asociado

Como se puede imaginar, la intención de returnsSomethingWithAwesomeness es devolver un parámetro basado en String o Int ok the key . El error que arroja el compilador tiene sentido porque no está permitido, pero da una idea de cómo arreglar la sintaxis.

func returnsSomethingWithAwesomeness<T: HasAwesomeness>(key: String) -> T { ... }

Bien, mi lectura es el método returnsSomethingWithAwesomeness es un método genérico que devuelve cualquier tipo T que tenga el subtipo HasAwesomness . Pero la siguiente implementación arroja más errores de tipo de tiempo de compilación:

func returnsSomethingWithAwesomeness<T: HasAwesomeness>(key: String) -> T { if key == "foo" { return "Amazing Foo" } else { return 42 } }

ERROR: el tipo ''T'' no se ajusta al protocolo ''StringLiteralConvertible''

ERROR: el tipo ''T'' no se ajusta al protocolo ''IntegerLiteralConvertible''

Bien, ahora estoy estancado. ¿Alguien me puede ayudar a llenar los vacíos en mi comprensión sobre tipos y genéricos, posiblemente apuntando a recursos útiles?