Menu
Coddy logo textTech

Métodos Genéricos

Parte da seção Object Oriented Programming do Journey de Rust da Coddy — lição 25 de 61.

Uma struct genérica pode conter qualquer tipo, mas não é muito útil sem métodos para interagir com seus dados. Para definir métodos para uma struct genérica, você precisa de uma sintaxe especial no bloco impl.

A chave é declarar o parâmetro genérico no próprio impl:

struct Wrapper<T> {
    value: T,
}

impl<T> Wrapper<T> {
    fn get(&self) -> &T {
        &self.value
    }
}

Observe o impl<T> antes de Wrapper<T>. Isso informa ao Rust que T é um parâmetro de tipo genérico para todo o bloco de implementação. Sem essa declaração, o Rust procuraria por um tipo concreto chamado T e falharia ao encontrá-lo.

O método get retorna &T—uma referência a qualquer tipo que o wrapper contenha. Isso funciona independentemente de T ser um inteiro, uma string ou qualquer outro tipo:

let num_wrapper = Wrapper { value: 100 };
let text_wrapper = Wrapper { value: "Rust" };

println!("{}", num_wrapper.get());  // 100
println!("{}", text_wrapper.get()); // Rust

A mesma definição de método funciona para ambos, porque o T genérico se adapta a cada tipo concreto em tempo de compilação.

challenge icon

Desafio

Fácil

Vamos estender seu contêiner genérico com métodos! Você construirá uma struct Box (não confundir com a Box padrão do Rust) que pode conter qualquer tipo e fornece métodos para interagir com seu conteúdo.

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

  • mybox.rs: Defina uma struct genérica pública chamada MyBox<T> com um campo privado contents do tipo T. Implemente métodos para esta struct:
    • Uma função associada new que cria um novo MyBox com o valor fornecido
    • Um método peek que retorna uma referência ao conteúdo (usando &self)
    • Um método replace que recebe um novo valor e substitui o conteúdo atual (usando &mut self)
  • main.rs: Importe seu módulo e demonstre os métodos genéricos funcionando com diferentes tipos. Você criará boxes, espiará seu conteúdo e substituirá valores para mostrar os métodos em ação.

Lembre-se da sintaxe principal para implementar métodos em uma struct genérica: você precisa de impl<T> antes de MyBox<T> para dizer ao Rust que T é um parâmetro genérico para todo o bloco de implementação.

No seu arquivo principal, demonstre seu MyBox ao:

  1. Criar um box com um número inteiro (primeira entrada, analisada como i32)
  2. Espiar seu conteúdo e imprimir o valor
  3. Substituir o conteúdo por um novo número inteiro (segunda entrada, analisada como i32)
  4. Espiar novamente para mostrar o valor atualizado
  5. Criar um segundo box com uma string (terceira entrada)
  6. Espiar o conteúdo do box de string

Sua saída deve seguir este formato:

Integer box contains: {value}
After replace: {value}
String box contains: {value}

Por exemplo, com as entradas 10, 25 e Rust:

Integer box contains: 10
After replace: 25
String box contains: Rust

Você receberá três entradas: um número inteiro inicial, um número inteiro de substituição e um valor de string.

Folha de consulta

Para definir métodos para uma struct genérica, declare o parâmetro genérico no bloco impl:

struct Wrapper<T> {
    value: T,
}

impl<T> Wrapper<T> {
    fn get(&self) -> &T {
        &self.value
    }
}

A sintaxe impl<T> informa ao Rust que T é um parâmetro de tipo genérico para todo o bloco de implementação. Sem isso, o Rust procuraria por um tipo concreto chamado T.

Métodos podem retornar referências ao tipo genérico (&T), o que funciona para qualquer tipo concreto:

let num_wrapper = Wrapper { value: 100 };
let text_wrapper = Wrapper { value: "Rust" };

println!("{}", num_wrapper.get());  // 100
println!("{}", text_wrapper.get()); // Rust

Experimente você mesmo

mod mybox;

use mybox::MyBox;

fn main() {
    // Ler as entradas
    let mut input1 = String::new();
    std::io::stdin().read_line(&mut input1).expect("Failed to read line");
    let initial_int: i32 = input1.trim().parse().expect("Invalid integer");

    let mut input2 = String::new();
    std::io::stdin().read_line(&mut input2).expect("Failed to read line");
    let replacement_int: i32 = input2.trim().parse().expect("Invalid integer");

    let mut input3 = String::new();
    std::io::stdin().read_line(&mut input3).expect("Failed to read line");
    let string_value = input3.trim().to_string();

    // TODO: Criar um MyBox com o inteiro inicial
    
    // TODO: Espiar seu conteúdo e imprimir: "Integer box contains: {value}"
    
    // TODO: Substituir o conteúdo pelo inteiro de substituição
    
    // TODO: Espiar novamente e imprimir: "After replace: {value}"
    
    // TODO: Criar um segundo MyBox com o valor da string
    
    // TODO: Espiar a caixa de string e imprimir: "String box contains: {value}"
}
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