Historia de la pregunta
En Rust no hay constructores clásicos como en los lenguajes de OOP, pero hay funciones asociadas (generalmente new) que implementan el patrón de constructores con inicialización explícita. Las funciones asociadas permiten crear instancias de estructuras con valores preestablecidos o crearlas con lógica adicional (por ejemplo, reservando memoria).
Problema
Muchos comienzan a usar solo new, olvidando otros patrones de métodos de fábrica (por ejemplo, with_capacity), o implementan incorrectamente la inicialización de las estructuras (especialmente con campos privados/públicos), lo que puede llevar a errores de invarianza.
Solución
La función asociada tipo new se implementa a través de impl, y puede ser el único punto de entrada para crear objetos con invariantes. Funciones como with_capacity ofrecen funcionalidades adicionales, como la posibilidad de alocar memoria por adelantado.
Ejemplo de código:
pub struct MyBuffer { data: Vec<u8>, } impl MyBuffer { pub fn new() -> Self { MyBuffer { data: Vec::new() } } pub fn with_capacity(cap: usize) -> Self { MyBuffer { data: Vec::with_capacity(cap) } } }
Características clave:
¿Si no se implementa new, Rust lo generará por defecto?
No. No hay generación automática de new. Si el método no está implementado explícitamente, no existirá, incluso si la estructura tiene solo campos públicos.
¿Cuál es la diferencia fundamental entre new y Default?
Default es un constructor de rasgos que solo puede ser llamado donde el tipo lo implemente o lo herede explícitamente. Es estándar para algoritmos genéricos, pero no siempre coincide con new.
¿Se pueden usar los métodos new y with_capacity para estructuras privadas?
Sí, los métodos pueden ser públicos o privados, pero crear un constructor público para una estructura privada no permite a los usuarios crear instancias de esa estructura fuera del módulo.
Estructura abierta sin invariantes, todos los campos son públicos:
pub struct User { pub login: String, pub active: bool }
Ventajas:
Desventajas:
Campos privados, creación solo a través de new, invariantes garantizados:
pub struct User { login: String, active: bool } impl User { pub fn new(login: String) -> User { User { login, active: true } } }
Ventajas:
Desventajas: