Médio Rust

Struct genérica com método que retorna referência

Enunciado

Crie uma struct genérica Caixa<T> que armazena um valor. Implemente um método obter que retorna uma referência ao valor armazenado. No main, crie uma Caixa com String e outra com i32, e imprima os valores usando obter.

Requisitos

  • A struct deve se chamar Caixa e ter um campo valor do tipo genérico T.
  • O método obter deve retornar &T.
  • O programa deve imprimir o conteúdo das duas caixas.

Código inicial

struct Caixa<T> {
    valor: T,
}

impl<T> Caixa<T> {
    // implemente obter
}

fn main() {
    // crie caixas e imprima
}

Saída esperada

Caixa de String: Rust
Caixa de i32: 42
Ver dica

O método obter recebe &self e retorna &T. Para imprimir, use println! com {}.

Mostrar solução
struct Caixa<T> {
    valor: T,
}

impl<T> Caixa<T> {
    // Retorna uma referência ao valor interno
    fn obter(&self) -> &T {
        &self.valor
    }
}

fn main() {
    let caixa_string = Caixa { valor: String::from("Rust") };
    let caixa_int = Caixa { valor: 42 };

    println!("Caixa de String: {}", caixa_string.obter());
    println!("Caixa de i32: {}", caixa_int.obter());
}

Passo a passo

  1. Definimos struct Caixa<T> com um campo valor: T. O parâmetro T é genérico.
  2. O bloco impl<T> Caixa<T> implementa métodos para qualquer T.
  3. O método obter(&self) -> &T devolve uma referência ao campo valor.
  4. No main, criamos Caixa { valor: String::from("Rust") }; o compilador infere T = String.
  5. Criamos Caixa { valor: 42 }; infere T = i32.
  6. Chamamos .obter() em cada caixa e imprimimos com {}.

Por que funciona

A struct genérica pode armazenar qualquer tipo. O método obter não precisa de trait bounds porque apenas acessa o campo. A monomorfização gera duas versões da struct e do método: uma para String e outra para i32. Isso mantém a segurança de tipos e evita duplicação de código.

Erros comuns

  • Esquecer o & no retorno: fn obter(&self) -> T tentaria mover o valor para fora da referência, causando erro. Use &T.
  • Não importar String: String::from está no prelúdio, então não precisa de import, mas se usar std::string::String explicitamente, importe.
  • Tentar imprimir sem {}: println!(caixa_string.obter()) não compila; use println!("{}", ...).

Outra forma de resolver

Poderia implementar Deref para acessar o valor diretamente, mas isso expõe o campo e pode não ser desejado. A referência explícita é mais clara.

Saída esperada

Caixa de String: Rust
Caixa de i32: 42