Menu
Coddy logo textTech

Retornando Tipos com Traits

Parte da seção Object Oriented Programming do Journey de Rust da Coddy. Lição 43 de 61.

Você usou limites de trait para restringir quais tipos uma function pode aceitar. Mas e quanto ao que uma function retorna? A sintaxe impl Trait permite especificar que uma function retorna "algum tipo que implements este trait" sem nomear o tipo concrete.

Veja a sintaxe em ação:

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!") }
}

O tipo de retorno impl Summary informa aos chamadores: "você receberá algo que implementa Summary." O chamador pode usar qualquer método do trait, mas não precisa saber que o tipo real é Article.

Isso é particularmente útil quando o tipo concrete é complexo ou quando você quer ocultar detalhes de implementação. A function promete uma capacidade (o trait), não um tipo específico.

No entanto, há uma limitação importante: a function deve return exatamente um único tipo concrete. Você não pode retornar types different condicionalmente que implement o mesmo trait. Isso requer objetos de trait, sobre os quais você aprenderá mais adiante.

// Isso funciona - sempre retorna Article
fn make_item() -> impl Summary {
    Article { headline: String::from("Hello") }
}

// Isso NÃO compilaria - dois tipos diferentes
// fn make_item(flag: bool) -> impl Summary {
//     if flag { Article { ... } } else { Tweet { ... } }
// }
challenge icon

Desafio

Fácil

Vamos criar uma fábrica de cartões de saudação que usa o tipo de retorno impl Trait para ocultar os detalhes da implementação! Você criará uma function que retorna "something that can greet" sem revelar o tipo concreto ao chamador.

Você organizará seu código em dois arquivos:

  • greetings.rs: Defina um Greet trait público com um greet method que recebe &self e retorna uma String. Em seguida, crie uma struct Card (ela não precisa ser pública!) com um campo message (String). Implemente o Greet trait para Card, retornando o message. Por fim, crie uma function pública chamada create_greeting que recebe um parâmetro String e retorna impl Greet. Essa function deve criar e retornar um Card com o message fornecido.
  • main.rs: Inclua seu módulo greetings e use o input fornecido para chamar create_greeting. A parte interessante é que seu arquivo principal não sabe nada sobre o tipo Card. Ele only sabe que recebeu algo que implements Greet. Chame o greet method no valor retornado e print o result.

A principal ideia é que Card permanece privado para o módulo, mas os chamadores ainda podem usá-lo por meio da interface do trait. A function promete uma capacidade (saudação), não um tipo específico.

Sua saída deve exibir a saudação:

{message}

Por exemplo, com o input Happy Birthday!:

Happy Birthday!

E com o input Congratulations on your promotion!:

Congratulations on your promotion!

Você receberá um input: o message de saudação.

Experimente você mesmo

mod greetings;

use greetings::Greet;

fn main() {
    // Leia a mensagem de saudação da 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: Chame create_greeting com a mensagem
    // Note: Você não conhece o tipo concreto - apenas que ele implementa Greet!
    
    // TODO: Chame o método greet e imprima o resultado
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Object Oriented Programming

Pratique por conta própria: Compilador de Rust online