En Rust, los enum no son simples listas de constantes como en otros lenguajes (como C o Java); son lo que se conoce como tipos de datos algebraicos. Esto significa que cada variante de un enum puede actuar como un contenedor de datos, permitiendo que una sola variable represente diferentes estados, cada uno con su propia estructura de información.

Existen tres formas principales de asociar datos a una variante:
1. Variantes de unidad: No contienen datos, funcionan como etiquetas simples (ej. Salir).
2. Variantes de tupla: Contienen una secuencia de valores sin nombres específicos (ej. Mover(i32, i32)).
3. Variantes de estructura: Contienen campos con nombres, de forma similar a un struct (ej. Escribir { mensaje: String }).

Esta capacidad es extremadamente poderosa porque permite modelar estados lógicos de forma segura. Si intentas acceder a los datos de una variante que no está presente, el compilador de Rust te lo impedirá. Es fundamental entender que el tipo de una variable es el enum completo, no la variante individual. Por lo tanto, el tamaño en memoria de un enum es determinado por la variante que más espacio ocupe, más un pequeño valor llamado “discriminante” que el sistema utiliza para identificar qué variante es cuál.

Si intentas crear un enum que se contenga a sí mismo (un enum recursivo), el compilador dará error porque el tamaño sería infinito; en esos casos, se debe usar un puntero Box<T> para dar un tamaño fijo.

#[derive(Debug)]
enum Comando {
    // Variante de unidad (sin datos)
    Detener,
    // Variante de tupla (datos anónimos)
    Mover(i32, i32),
    // Variante de estructura (campos con nombre)
    Texto { contenido: String, autor: String },
}

impl Comando {
    // Definición de métodos para el enum
    fn ejecutar(&self) {
        match self {
            Comando::Detener => println!("Deteniendo el sistema..."),
            Comando::Mover(x, y) => {
                println!("Moviendo a la posición: x={}, y={}", x, y);
            }
            Comando::Texto { contenido, autor } => {
                println!("Mensaje de {}: \"{}\"", autor, contenido);
            }
        }
    }
}

fn main() {
    // Instanciación de diferentes variantes
    let accion1 = Comando::Detener;
    let accion2 = Comando::Mover(10, 25);
    let accion3 = Comando::Texto {
        contenido: String::from("Hola, Rust!"),
        autor: String::from("Programador"),
    };

    // Uso del método implementado
    accion1.ejecutar();
    accion2.ejecutar();
    accion3.ejecutar();

    // Uso de #[derive(Debug)] para inspección
    println!("Estado de accion3: {:?}", accion3);
}

Explicación del Código


* #[derive(Debug)]: Este atributo permite que el tipo Comando pueda ser impreso mediante el formateador {:?} para depuración.
* enum Comando: Define nuestro tipo de dato algebraico con tres tipos de variantes distintas.
* Comando::Detener: Es una variante de unidad que no almacena información.
* Comando::Mover(i32, i32): Es una variante de tupla que encapsula dos enteros.
* Comando::Texto { contenido: String, autor: String }: Es una variante de estructura con campos nombrados.
* impl Comando: Bloque donde definimos métodos para nuestro enum.
* fn ejecutar(&self): Un método que recibe una referencia a self (la instancia del enum) para inspeccionarla.
* match self: Estructura de control que desestructura la variante para extraer sus valores internos.
* Comando::Mover(x, y): En el match, las variables x e y capturan los valores de la tupla de Comando::Mover.
* Comando::Texto { contenido, autor }: Utiliza el patrón de desestructuración para asignar los campos contenido y autor a variables locales.
* accion1, accion2, accion3: Son variables de tipo Comando que contienen instancias de cada variante.

38