Da trilha de Rust Este conceito ainda não saiu como card do dia. ir para o card de hoje

Rust Genéricos Intermediário

Genéricos

Genéricos em Rust permitem escrever código que funciona com múltiplos tipos sem duplicação, mantendo a segurança de tipos. Eles são resolvidos em tempo de compilação: o compilador gera uma versão especializada para cada tipo concreto usado, processo chamado monomorfização.

Funções genéricas usam parâmetros de tipo, como fn maior<T>(a: T, b: T) -> T. Para restringir os tipos aceitos, usamos trait bounds, por exemplo T: PartialOrd, que garantem que o tipo implemente os métodos necessários. A sintaxe where deixa as restrições mais legíveis em assinaturas complexas.

Genéricos são amplamente usados na biblioteca padrão: Vec<T>, Option<T>, Result<T, E> e funções como std::cmp::max. Eles evitam custo em tempo de execução, pois não há despacho dinâmico a menos que se use dyn Trait.

Pontos-chave

  • Funções genéricas usam parâmetros de tipo entre <> e podem ter múltiplos tipos.
  • Trait bounds (T: Trait) restringem os tipos que podem ser usados com a função.
  • A cláusula where é equivalente a trait bounds, mas melhora a legibilidade.
  • Monomorfização gera código especializado para cada tipo concreto em tempo de compilação.
  • Genéricos não têm custo de desempenho em relação a código escrito manualmente para cada tipo.
genericos.rs
// Função genérica com trait bound: T deve implementar PartialOrd
fn maior<T: PartialOrd>(a: T, b: T) -> T {
    if a > b { a } else { b }
}

// Usando where para múltiplos bounds
fn imprime_maior<T>(a: T, b: T)
where
    T: PartialOrd + std::fmt::Display,
{
    let m = if a > b { a } else { b };
    println!("O maior é: {}", m);
}

// Struct genérica
struct Par<T> {
    primeiro: T,
    segundo: T,
}

impl<T: PartialOrd + Copy> Par<T> {
    fn maior(&self) -> T {
        if self.primeiro > self.segundo {
            self.primeiro
        } else {
            self.segundo
        }
    }
}

fn main() {
    // Monomorfização: o compilador gera versões para i32 e f64
    println!("{}", maior(10, 20));
    println!("{}", maior(3.14, 2.71));

    imprime_maior(100, 200);

    let par = Par { primeiro: 5, segundo: 8 };
    println!("Maior do par: {}", par.maior());
}

Exercícios

  1. 1
    Fácil

    Função genérica para somar dois valores

    Escreva uma função genérica somar que recebe dois valores do mesmo tipo e retorna a soma. Use trait bound para permitir apenas tipos que implementem std::ops::Add. Teste com i32 e f64.

    Resolver
  2. 2
    Médio

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

    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.

    Resolver
  3. 3
    Desafio

    Função genérica com múltiplos bounds e where

    Escreva uma função genérica maior_e_imprime que recebe dois valores do mesmo tipo, encontra o maior e o imprime. A função deve funcionar para tipos que implementem PartialOrd e Display. Use a cláusula where para os bounds. No main, chame a função com i32, f64 e &str.

    Resolver

Continue estudando