Menu
Coddy logo textTech

Implementaciones por defecto

Parte de la sección Object Oriented Programming del Journey de Rust de Coddy — lección 31 de 61.

Hasta ahora, cada método de trait que hemos definido ha sido solo una firma: un requisito sin cuerpo. ¿Pero qué pasa si la mayoría de los tipos que implementan un trait usaran la misma lógica? Rust te permite proporcionar una implementación predeterminada directamente en la definición del trait.

En lugar de terminar la firma del método con un punto y coma, se añade un cuerpo:

trait Greet {
    fn greet(&self) -> String {
        String::from("Hello there!")
    }
}

Ahora cualquier tipo que implemente Greet obtiene automáticamente este método, sin escribir ningún código en el bloque impl:

struct Guest;

impl Greet for Guest {}

let visitor = Guest;
println!("{}", visitor.greet());  // ¡Hola!

La implementación vacía impl Greet for Guest {} es válida porque el trait ya proporciona el comportamiento. La estructura simplemente se "adhiere" al trait y recibe el método predeterminado de forma gratuita.

Este patrón es útil cuando quieres definir un comportamiento compartido que funcione para la mayoría de los casos. Los tipos que necesiten algo diferente pueden sobrescribir el comportamiento predeterminado (que aprenderás a continuación), mientras que los tipos que estén conformes con el comportamiento estándar no necesitan repetirse.

challenge icon

Desafío

Fácil

¡Exploremos el poder de las implementaciones por defecto construyendo un sistema de notificaciones! Crearás un trait que proporcione un comportamiento estándar de fábrica, para que los tipos puedan optar por él sin escribir código repetitivo.

Organizarás tu código en tres archivos:

  • notifiable.rs: Define un trait público Notifiable con un método notify(&self) -> String que tenga una implementación por defecto. El valor por defecto debe devolver "You have a new notification!". Cualquier tipo que implemente este trait recibirá automáticamente este comportamiento sin necesidad de escribir nada en su bloque impl.
  • alerts.rs: Crea dos structs de unidad públicos simples que implementen tu trait:
    • EmailAlert — implementa Notifiable con un bloque impl vacío (usa el valor por defecto)
    • SystemAlert — también implementa Notifiable con un bloque impl vacío (usa el valor por defecto)
    ¡Ambos structs obtendrán automáticamente el mensaje de notificación por defecto sin que tengas que escribir ningún cuerpo de método!
  • main.rs: Une tus módulos y demuestra cómo ambos tipos de alerta comparten el mismo comportamiento por defecto. Crea instancias de ambos structs y llama a sus métodos notify.

En tu archivo principal, crea un EmailAlert y un SystemAlert, luego imprime sus notificaciones en líneas separadas.

Tu salida debería ser:

You have a new notification!
You have a new notification!

Observa cómo ambos tipos producen una salida idéntica: ¡esa es la belleza de las implementaciones por defecto! Ningún struct necesitó escribir código para el método notify, y sin embargo, ambos tienen un comportamiento de notificación plenamente funcional. En la siguiente lección, aprenderás cómo sobrescribir estos valores por defecto cuando un tipo necesite un comportamiento personalizado.

Hoja de referencia

Los métodos de los traits pueden tener implementaciones por defecto proporcionando un cuerpo de método en lugar de solo una firma:

trait Greet {
    fn greet(&self) -> String {
        String::from("Hello there!")
    }
}

Los tipos que implementan el trait reciben automáticamente el comportamiento por defecto sin escribir ningún código:

struct Guest;

impl Greet for Guest {}

let visitor = Guest;
println!("{}", visitor.greet());  // ¡Hola!

Un bloque impl vacío es válido cuando el trait proporciona implementaciones por defecto. Esto permite que los tipos opten por un comportamiento compartido sin repetición.

Pruébalo tú mismo

mod notifiable;
mod alerts;

use notifiable::Notifiable;
use alerts::{EmailAlert, SystemAlert};

fn main() {
    // TODO: Crear una instancia de EmailAlert
    
    // TODO: Crear una instancia de SystemAlert
    
    // TODO: Imprimir la notificación de EmailAlert
    
    // TODO: Imprimir la notificación de SystemAlert
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Object Oriented Programming