Sobrescribir valores por defecto
Parte de la sección Programación Orientada a Objetos del Journey de Rust de Coddy. Lección 32 de 61.
Las implementaciones predeterminadas son prácticas, pero a veces un tipo necesita un comportamiento diferente del estándar. Cuando esto sucede, puedes reemplazar el valor predeterminado proporcionando tu propia implementación en el bloque impl.
Simplemente define el método con la misma firma, pero incluye tu lógica personalizada:
trait Greet {
fn greet(&self) -> String {
String::from("Hello there!")
}
}
struct Robot {
id: u32,
}
impl Greet for Robot {
fn greet(&self) -> String {
format!("BEEP BOOP. Unit {} online.", self.id)
}
}
Aunque Greet proporciona un método greet predeterminado, Robot lo reemplaza por completo con su propia versión. Cuando llamas a greet() en un Robot, Rust utiliza la implementación personalizada:
let bot = Robot { id: 42 };
println!("{}", bot.greet()); // BEEP BOOP. Unidad 42 en línea.
Esto te da flexibilidad: los tipos que están conformes con el comportamiento predeterminado no necesitan escribir nada, mientras que los tipos que necesitan un comportamiento especializado pueden sobrescribir solo los métodos que les interesan. El trait sigue garantizando que todos los tipos que lo implementan tengan el método disponible.
Desafío
Fácil¡Construyamos un sistema de notificaciones en el que distintos tipos de alertas puedan personalizar sus mensajes! Crearás un trait con una implementación predeterminada; después, harás que un tipo use la predeterminada mientras otro la sobrescribe con un comportamiento personalizado.
Organizarás tu código en tres archivos:
notifiable.rs: Define un trait públicoNotifiablecon un métodonotify(&self) -> Stringque tenga una implementación predeterminada que devuelva"Alert: Something happened!".alerts.rs: Crea dos estructuras públicas que implementen tu trait de forma diferente:GenericAlert: una estructura unitaria que usa la notificación predeterminada (bloque impl vacío)UrgentAlert: una estructura con un campo públicomessage(String) que sobrescribe la implementación predeterminada para devolver"URGENT: {message}", donde{message}es su mensaje almacenado
main.rs: Reúne tus módulos y demuestra ambos comportamientos. Crea unGenericAlerty unUrgentAlertusando la entrada proporcionada; después, imprime sus notificaciones.
La idea clave es que GenericAlert obtiene un comportamiento gratuito de la implementación predeterminada, mientras que UrgentAlert proporciona su propia versión especializada al definir el método en su bloque impl.
Tu salida debe seguir este formato:
Alert: Something happened!
URGENT: {message}Por ejemplo, con la entrada Server is down!:
Alert: Something happened!
URGENT: Server is down!Recibirás una entrada: el mensaje de la alerta urgente.
Pruébalo tú mismo
mod notifiable;
mod alerts;
use alerts::{GenericAlert, UrgentAlert};
use notifiable::Notifiable;
fn main() {
// Lee la entrada para el mensaje de la alerta urgente
let mut input = String::new();
std::io::stdin().read_line(&mut input).expect("Failed to read line");
let message = input.trim().to_string();
// TODO: Crea una instancia de GenericAlert
// TODO: Crea una instancia de UrgentAlert con el mensaje de entrada
// TODO: Imprime la notificación de GenericAlert
// TODO: Imprime la notificación de UrgentAlert
}
Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.
Todas las lecciones de Programación Orientada a Objetos
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 multimediaPractica por tu cuenta: Compilador de Rust online