Las structs (estructuras) en Rust son tipos de datos personalizados que permiten agrupar múltiples valores relacionados bajo un mismo nombre. A diferencia de los arreglos, donde todos los elementos deben ser del mismo tipo, en una struct cada campo puede tener un tipo de dato distinto, permitiendo modelar objetos complejos como una coordenada, un usuario o un producto.

Para definir una struct, se utiliza la palabra clave struct seguida del nombre de la estructura y un bloque con sus campos y tipos. Una vez definida, para crear una instancia (instanciación), se debe proporcionar un valor para cada uno de sus campos utilizando la sintaxis nombre_campo: valor. Si el nombre de una variable local coincide exactamente con el nombre de un campo de la struct, puedes usar la sintaxis de campo abreviado para simplificar el código.

El acceso a los datos de una instancia se realiza mediante el operador de punto (.). Es fundamental entender que en Rust la mutabilidad se aplica a la instancia completa: si declaras una variable como mut, todos sus campos pueden ser modificados; si es inmutable, ninguno podrá ser alterado.

Para facilitar la creación de nuevas instancias basadas en otras ya existentes, Rust ofrece la “sintaxis de actualización de struct” mediante el operador ... Esto permite copiar todos los valores de una instancia previa y solo especificar los campos que desean cambiar. Finalmente, las structs son tipos nominales, lo que significa que dos estructuras con los mismos campos y tipos son tratadas como tipos completamente diferentes por el compilador. Para poder visualizar el contenido de una struct durante la depuración, se debe usar el atributo #[derive(Debug)] para implementar automáticamente el trait Debug.

#[derive(Debug)]
struct Punto {
    x: f64,
    y: f64,
}

#[derive(Debug)]
struct Rectangulo {
    ancho: f64,
    alto: f64,
}

fn main() {
    // 1. Instanciación estándar
    let punto1 = Punto { x: 1.0, y: 2.0 };
    println!("Punto 1: {:?}", punto1);

    // 2. Sintaxis de campo abreviado
    let x = 10.0;
    let y = 20.0;
    let punto_abreviado = Punto { x, y };
    println!("Punto abreviado: {:#?}", punto_abreviado);

    // 3. Acceso a campos
    println!("La coordenada x de punto1 es: {}", punto1.x);

    // 4. Mutabilidad de la instancia
    let mut punto_mutante = Punto { x: 5.0, y: 5.0 };
    punto_mutante.x = 10.0; // El campo x se modifica porque la instancia es mut
    println!("Punto mutante: {:?}", punto_mutante);

    // 5. Sintaxis de actualización de struct
    let rect = Rectangulo { ancho: 10.0, alto: 20.0 };
    let rect_copiado = Rectangulo { ancho: 50.0, ..rect }; // Copia 'alto' de 'rect'
    println!("Rectángulo copiado (ancho cambiado): {:?}", rect_copiado);
}

Explicación del Código

  • #[derive(Debug)]: Atributo colocado sobre Punto y Rectangulo para permitir su impresión mediante {:?} o {:#?}.
  • struct Punto: Definición de la estructura con dos campos, x e y, ambos de tipo f64.
  • punto1: Se instancia de forma estándar asignando 1.0 a x y 2.0 a y.
  • punto_abreviado: Utiliza la sintaxis abreviada al pasar las variables x y y directamente, ya que sus nombres coinciden con los campos de la struct.
  • punto1.x: Accede directamente al valor almacenado en el campo x de la instancia punto1.
  • punto_mutante: Al declararse con let mut, permite modificar el valor de su campo x mediante la asignación punto_mutante.x = 10.0.
  • rect_copiado: Utiliza la sintaxis de actualización ..rect para crear una nueva instancia de Rectangulo que hereda el campo alto de rect, pero redefine el campo ancho con un valor de 50.0.

35