Los generics (tipos genéricos) permiten definir funciones y tipos flexibles y reutilizables. Una característica clave de Swift es la preservación de la seguridad de tipo: el compilador verifica el trabajo con tipos específicos en tiempo de compilación. Los tipos genéricos se pueden restringir a través de condiciones where, herencia de protocolos y combinaciones de estos.
Ejemplo de código:
func swapValues<T>(_ a: inout T, _ b: inout T) { let temp = a a = b b = temp } protocol Drawable { func draw() } func drawAll<T: Drawable>(_ items: [T]) { for item in items { item.draw() } } // Restricción por protocolo y condición where func compareValues<T: Equatable>(_ a: T, _ b: T) -> Bool { return a == b }
¿Pueden las funciones genéricas actuar como funciones sobrecargadas? ¿Cómo elige el compilador la implementación necesaria?
Respuesta: Sí, las funciones genéricas pueden estar sobrecargadas con funciones normales y otras funciones genéricas. El compilador intenta elegir la implementación más específica. Ejemplo:
func printValue(_ value: Int) { print("Int: \(value)") } func printValue<T>(_ value: T) { print("Genérico: \(value)") } printValue(5) // Int: 5 printValue("Swift") // Genérico: Swift
Historia
El equipo escribió una extensión genérica de un array para buscar un índice, olvidando restringir el tipo a través de Equatable. Esto llevó a un error de compilación al intentar aplicar la extensión a un array con elementos no Equatable.
Historia
En el proyecto intentaron implementar un caché de objetos genéricos sin restricción de tipo. Como resultado, al intentar hacer downcast en tiempo de ejecución surgieron crashes; el uso seguro real podría haberse logrado a través de protocolos con associated type y constraints.
Historia
Los desarrolladores implementaron una clase genérica, pero al heredar y sobrescribir olvidaron la necesidad de especificar el parámetro genérico completo del heredero. Como resultado, el código no se compilaba y se requería una reestructuración completa de la jerarquía de tipos.