Métodos en Enums
Parte de la sección Object Oriented Programming del Journey de Rust de Coddy — lección 15 de 61.
Al igual que los structs, los enums pueden tener métodos definidos en bloques impl. Esto te permite adjuntar comportamiento directamente a tu tipo enum, facilitando el trabajo con diferentes variantes a través de una interfaz unificada.
Aquí se explica cómo añadir un método al enum Message de la lección anterior:
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
}
impl Message {
fn describe(&self) -> String {
match self {
Message::Quit => String::from("Quit signal"),
Message::Move { x, y } => format!("Move to ({}, {})", x, y),
Message::Write(text) => format!("Message: {}", text),
}
}
}
El bloque impl Message funciona exactamente igual que para las estructuras. El método toma &self para acceder a la instancia del enum. Dentro del método, usas match para determinar con qué variante estás tratando y devolver el resultado apropiado.
Llamar al método se ve igual independientemente de qué variante tengas:
fn main() {
let m1 = Message::Quit;
let m2 = Message::Move { x: 10, y: 20 };
println!("{}", m1.describe()); // Señal de salida
println!("{}", m2.describe()); // Mover a (10, 20)
}
Este patrón es potente porque el llamador no necesita saber qué variante tiene; simplemente llama al método y el enum se encarga del resto internamente. El comportamiento cambia según la variante, pero la interfaz se mantiene consistente.
Desafío
FácilVamos a construir un sistema de semáforo que utiliza un enum con métodos para describir el estado actual de la señal. Cada color de luz llevará información sobre cuánto tiempo dura, y un método proporcionará una descripción legible para los humanos.
Crearás dos archivos para organizar tu código:
traffic.rs: Define un enum públicoTrafficLightcon tres variantes:Red— contiene unu32que representa los segundos de esperaYellow— contiene unu32que representa los segundos de esperaGreen— contiene unu32que representa los segundos para avanzar
statusque devuelva unStringdescribiendo la luz. Usamatchdentro del método para manejar cada variante e incluir la duración en el mensaje.main.rs: Importa tu módulo de tráfico, crea instancias de cada variante de luz y llama al métodostatusen cada una para imprimir las descripciones.
El método status debe devolver mensajes en estos formatos exactos:
- Para
Red:Stop for {seconds} seconds - Para
Yellow:Caution for {seconds} seconds - Para
Green:Go for {seconds} seconds
Tu salida debe mostrar el estado de cada luz en su propia línea:
Stop for {seconds} seconds
Caution for {seconds} seconds
Go for {seconds} secondsPor ejemplo, con una luz roja de 30 segundos, amarilla de 5 segundos y verde de 25 segundos, la salida sería:
Stop for 30 seconds
Caution for 5 seconds
Go for 25 secondsRecibirás tres entradas: la duración de la luz roja, la duración de la luz amarilla y la duración de la luz verde.
Hoja de referencia
Los enums pueden tener métodos definidos en bloques impl, al igual que los structs:
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
}
impl Message {
fn describe(&self) -> String {
match self {
Message::Quit => String::from("Quit signal"),
Message::Move { x, y } => format!("Move to ({}, {})", x, y),
Message::Write(text) => format!("Message: {}", text),
}
}
}
Los métodos toman &self para acceder a la instancia del enum y usan match para manejar las diferentes variantes:
let m1 = Message::Quit;
let m2 = Message::Move { x: 10, y: 20 };
println!("{}", m1.describe()); // Señal de salida
println!("{}", m2.describe()); // Mover a (10, 20)
El llamador utiliza la misma interfaz independientemente de la variante; el enum maneja el comportamiento internamente basándose en qué variante es.
Pruébalo tú mismo
mod traffic;
use traffic::TrafficLight;
fn main() {
// Lee la entrada para las duraciones
let mut red_input = String::new();
std::io::stdin().read_line(&mut red_input).expect("Failed to read line");
let red_duration: u32 = red_input.trim().parse().expect("Invalid number");
let mut yellow_input = String::new();
std::io::stdin().read_line(&mut yellow_input).expect("Failed to read line");
let yellow_duration: u32 = yellow_input.trim().parse().expect("Invalid number");
let mut green_input = String::new();
std::io::stdin().read_line(&mut green_input).expect("Failed to read line");
let green_duration: u32 = green_input.trim().parse().expect("Invalid number");
// TODO: Crea instancias de cada variante de TrafficLight con las duraciones de entrada
// TODO: Llama al método status en cada luz e imprime el resultado
}
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