Enums con datos
Parte de la sección Object Oriented Programming del Journey de Rust de Coddy — lección 14 de 61.
Los enums básicos en Rust te permiten definir un tipo con un conjunto fijo de variantes—como Direction::North o Status::Active. Pero los enums de Rust son mucho más potentes que eso. Cada variante puede contener sus propios datos, lo que hace que los enums sean increíblemente flexibles para modelar escenarios del mundo real.
Considera un sistema de mensajería donde diferentes tipos de mensajes llevan información diferente. Un mensaje de texto tiene contenido, un comando de movimiento tiene coordenadas y una señal de salida no tiene nada en absoluto. En Rust, puedes representar todo esto con un solo enum:
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(u8, u8, u8),
}
Cada variante tiene una forma diferente. Quit no contiene datos; es solo una señal.
Move utiliza una sintaxis similar a una estructura con campos con nombre. Write contiene una única String utilizando sintaxis de tupla. ChangeColor contiene tres valores que representan componentes RGB.
La creación de instancias de estas variantes se ve así:
let m1 = Message::Quit;
let m2 = Message::Move { x: 10, y: 20 };
let m3 = Message::Write(String::from("Hello"));
let m4 = Message::ChangeColor(255, 128, 0);
La belleza de este enfoque es que m1, m2, m3 y m4 son todos del mismo tipo: Message. Puedes almacenarlos en la misma colección, pasarlos a la misma función o devolver cualquier variante desde una sola función. El enum unifica diferentes formas de datos bajo un solo tipo mientras preserva la información específica que cada variante necesita.
Desafío
FácilVamos a construir un sistema de notificaciones que utiliza enums con datos para representar diferentes tipos de alertas. Cada tipo de notificación lleva información diferente: algunas tienen mensajes, otras tienen valores numéricos y otras son simples señales.
Crearás dos archivos para organizar tu código:
notification.rs: Define un enumNotificationpúblico con tres variantes:Alert— contiene un único mensajeString(sintaxis de tupla)Reminder— contiene campos con nombre:title(String) yminutes(u32)Dismiss— no contiene datos, es solo una señal
main.rs: Importa tu módulo de notificación y crea una instancia de cada variante. Luego, imprime la información de cada notificación para demostrar que las tres variantes son del mismo tipo pero contienen datos diferentes.
Al imprimir, utiliza el formateo de depuración ({:?}) para mostrar cada notificación. Necesitarás derivar el trait Debug en tu enum para que pueda imprimirse de esta manera.
Tu salida debería mostrar las tres notificaciones, cada una en su propia línea:
Alert("{message}")
Reminder { title: "{title}", minutes: {minutes} }
DismissPor ejemplo, con un mensaje de alerta de "Server down", un recordatorio con el título "Meeting" y 30 minutos, la salida sería:
Alert("Server down")
Reminder { title: "Meeting", minutes: 30 }
DismissRecibirás tres entradas: el mensaje de alerta, el título del recordatorio y los minutos del recordatorio.
Hoja de referencia
Las variantes de los enums en Rust pueden contener diferentes tipos de datos, lo que las hace potentes para modelar diversos escenarios bajo un solo tipo.
Definición de enums con datos
Cada variante puede tener su propia estructura de datos:
enum Message {
Quit, // Sin datos
Move { x: i32, y: i32 }, // Campos con nombre (tipo struct)
Write(String), // Valor único (sintaxis de tupla)
ChangeColor(u8, u8, u8), // Múltiples valores (sintaxis de tupla)
}
Creación de instancias de enums
let m1 = Message::Quit;
let m2 = Message::Move { x: 10, y: 20 };
let m3 = Message::Write(String::from("Hello"));
let m4 = Message::ChangeColor(255, 128, 0);
Todas las instancias son del mismo tipo (Message) a pesar de contener datos diferentes, lo que permite almacenarlas en colecciones, pasarlas a funciones o devolverlas desde funciones de manera uniforme.
Trait Debug
Para imprimir enums usando el formato {:?}, derive el trait Debug:
#[derive(Debug)]
enum Message {
// variantes...
}
Pruébalo tú mismo
mod notification;
use notification::Notification;
fn main() {
// Leer entradas
let mut alert_message = String::new();
std::io::stdin().read_line(&mut alert_message).expect("Failed to read line");
let alert_message = alert_message.trim().to_string();
let mut reminder_title = String::new();
std::io::stdin().read_line(&mut reminder_title).expect("Failed to read line");
let reminder_title = reminder_title.trim().to_string();
let mut minutes_input = String::new();
std::io::stdin().read_line(&mut minutes_input).expect("Failed to read line");
let reminder_minutes: u32 = minutes_input.trim().parse().expect("Failed to parse minutes");
// TODO: Crear una notificación de tipo Alert usando alert_message
// TODO: Crear una notificación de tipo Reminder usando reminder_title y reminder_minutes
// TODO: Crear una notificación de tipo Dismiss
// TODO: Imprimir cada notificación usando el formato de depuración {:?}
// Cada notificación debe imprimirse en su propia línea
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Object Oriented Programming
1Métodos y Comportamiento
Intro a Bloques de ImplementaciónEl Parámetro SelfMétodos MutablesFunciones AsociadasMúltiples Bloques de ImplementaciónEncadenamiento de MétodosResumen - Acciones de Rectángulo4Proyecto: Mascota virtual
Definir la mascotaAlimentar a la mascota7Traits estándar
El trait DebugEl trait DisplayClone y CopyTraits de igualdadResumen - Punto imprimible10Proyecto: Sistema de documentos
El Trait DrawComponente de texto2Encapsulamiento y módulos
Conceptos básicos de módulosLa palabra clave PublicCampos privadosGettersSettersRepaso - Casillero seguro5Genéricos
Estructuras genéricasMétodos genéricosMúltiples tipos genéricosFunciones genéricasResumen - Punto de coordenadas8Traits como límites
Sintaxis de límites de traitsLímites múltiplesLa cláusula whereRetornar tipos con traitsResumen: Impresora genérica11Patrones de diseño en Rust
Patrón NewtypeComposiciónEl Trait DropFrom e IntoResumen - Mock de Smart Pointer3Enums avanzados
Enums con datosMétodos en EnumsCoincidencia de variantes de datosEl Enum Option revisitadoResumen - Enum Shape6Definición de Traits
¿Qué es un Trait?Implementación de TraitsImplementaciones por defectoSobrescribir valores por defectoTraits con parámetrosResumen - Reproductor multimedia