Menu
Coddy logo textTech

Retornar tipos con traits

Parte de la sección Programación Orientada a Objetos del Journey de Rust de Coddy. Lección 43 de 61.

Has utilizado límites de traits para restringir qué tipos puede aceptar una función. Pero ¿qué ocurre con lo que una función devuelve? La sintaxis impl Trait te permite especificar que una función devuelve «algún tipo que implementa este trait» sin nombrar el tipo concreto.

Aquí tienes la sintaxis en acción:

trait Summary {
    fn summarize(&self) -> String;
}

struct Article {
    headline: String,
}

impl Summary for Article {
    fn summarize(&self) -> String {
        self.headline.clone()
    }
}

fn create_summary() -> impl Summary {
    Article { headline: String::from("Breaking News!") }
}

El tipo de retorno impl Summary indica a quienes realizan la llamada «obtendrás algo que implementa Summary». Quien realiza la llamada puede usar cualquier método del trait, pero no necesita saber que el tipo real es Article.

Esto es especialmente útil cuando el tipo concreto es complejo o cuando quieres ocultar los detalles de implementación. La función promete una capacidad (el trait), no un tipo específico.

Sin embargo, hay una limitación importante: la función debe devolver exactamente un tipo concreto. No puedes devolver condicionalmente tipos diferentes que implementen el mismo trait. Eso requiere objetos de trait, que aprenderás más adelante.

// Esto funciona - siempre devuelve Article
fn make_item() -> impl Summary {
    Article { headline: String::from("Hello") }
}

// Esto NO compilaría - dos tipos diferentes
// fn make_item(flag: bool) -> impl Summary {
//     if flag { Article { ... } } else { Tweet { ... } }
// }
challenge icon

Desafío

Fácil

¡Construyamos una fábrica de tarjetas de felicitación que use el tipo de retorno impl Trait para ocultar los detalles de implementación! Crearás una función que devuelva «algo que pueda saludar» sin revelar el tipo concreto al usuario que la llama.

Organizarás tu código en dos archivos:

  • greetings.rs: Define un trait público Greet con un método greet que tome &self y devuelva un String. Después, crea una estructura Card (¡no necesita ser pública!) con un campo message (String). Implementa el trait Greet para Card, devolviendo el mensaje. Por último, crea una función pública llamada create_greeting que tome un parámetro String y devuelva impl Greet. Esta función debe crear y devolver un Card con el mensaje proporcionado.
  • main.rs: Incluye tu módulo greetings y usa la entrada proporcionada para llamar a create_greeting. Lo interesante aquí es que tu archivo principal no conoce el tipo Card en absoluto. Solo sabe que recibió algo que implementa Greet. Llama al método greet sobre el valor devuelto e imprime el resultado.

La idea clave es que Card permanece privado dentro del módulo, pero quienes llaman a la función aún pueden usarlo a través de la interfaz del trait. La función promete una capacidad (saludar), no un tipo específico.

Tu salida debe mostrar el saludo:

{message}

Por ejemplo, con la entrada Happy Birthday!:

Happy Birthday!

Y con la entrada Congratulations on your promotion!:

Congratulations on your promotion!

Recibirás una entrada: el mensaje de saludo.

Pruébalo tú mismo

mod greetings;

use greetings::Greet;

fn main() {
    // Lee el mensaje de saludo desde la entrada
    let mut input = String::new();
    std::io::stdin().read_line(&mut input).expect("Failed to read line");
    let message = input.trim().to_string();

    // TODO: Llama a create_greeting con el mensaje
    // Note: No conoces el tipo concreto - ¡solo que implementa Greet!
    
    // TODO: Llama al método greet e imprime el resultado
}
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 Programación Orientada a Objetos

Practica por tu cuenta: Compilador de Rust online