Historia de la cuestión: La eliminación de tipo (type erasure) es un patrón que apareció en Swift como respuesta a las limitaciones de los protocolos con associated type o requisitos de Self. Un protocolo no se puede utilizar como un tipo directamente sin la eliminación de tipo, si contiene tipos asociados, ya que el compilador no conoce la implementación específica. Esto se encuentra a menudo al crear contenedores de datos, colecciones, flujos, donde la abstracción es importante.
Problema: Si hay un protocolo con associatedtype, por ejemplo:
protocol Animal { associatedtype Food func eat(_ food: Food) }
no se puede declarar una variable del tipo Animal. Necesitamos un tipo "que elimina" que permita referirse a diferentes tipos concretos a través de la abstracción:
let zoo: [any Animal] // Error de compilación
Solución: La eliminación de tipo se implementa utilizando envoltorios (por ejemplo, el patrón Box o struct AnyXxx), proporcionando una interfaz única, ocultando los detalles del tipo real:
struct AnyAnimal<F>: Animal { private let _eat: (F) -> Void init<A: Animal>(_ base: A) where A.Food == F { _eat = base.eat } func eat(_ food: F) { _eat(food) } }
Ahora se pueden almacenar diferentes implementaciones de Animal con el mismo Food:
let animals: [AnyAnimal<Grass>] = [AnyAnimal(Cow()), AnyAnimal(Sheep())]
Características clave:
¿Se puede utilizar un protocolo con associatedtype sin la eliminación de tipo como tipo de propiedad o matriz?
No, no se puede. El compilador requiere la especificación de todos los tipos asociados. Por ejemplo, la siguiente declaración provocará un error:
let array: [Animal] // Error: 'Animal' solo puede usarse como una restricción genérica
¿Puede la eliminación de tipo reemplazar la herencia?
No, la eliminación de tipo no es un reemplazo completo de la herencia. Resuelve el problema de la abstracción para protocolos con associatedtype, mientras que la herencia se utiliza para implementar lógica común y reutilizar código entre clases.
¿Es necesario implementar todos los métodos y propiedades del protocolo dentro de la envoltura de eliminación de tipo?
Sí, es obligatorio. La eliminación de tipo funciona solo si la envoltura repite completamente la interfaz externa del protocolo, de lo contrario, parte de la funcionalidad estará oculta.
En un proyecto en producción, todo el trabajo con las fuentes de datos se basa en la eliminación de tipo, incluso cuando no hay necesidad de associatedtype. El código se vuelve difícil de mantener, los nuevos desarrolladores se confunden.
Ventajas:
Desventajas:
La eliminación de tipo se aplica solo para la abstracción de la fuente de datos, que encapsula diferentes estrategias de carga (redes, locales), cada una con sus propios tipos. En el resto, el código es transparente.
Ventajas:
Desventajas: