Implementando traits em tipos

1. Fundamentos da Implementação de Traits

Em Rust, traits são o mecanismo principal para definir comportamento compartilhado entre tipos. A implementação de um trait segue a sintaxe impl <Trait> for <Tipo>:

trait Saudacao {
    fn saudar(&self) -> String;
}

struct Pessoa {
    nome: String,
}

impl Saudacao for Pessoa {
    fn saudar(&self) -> String {
        format!("Olá, meu nome é {}", self.nome)
    }
}

Regras de coerência (Orphan Rule): Você só pode implementar um trait para um tipo se pelo menos um deles (trait ou tipo) for definido no seu crate. Isso evita ambiguidades e conflitos entre bibliotecas.

// ERRO: Não podemos implementar um trait externo para um tipo externo
// impl Display for Vec<String> { ... } // Isso exigiria modificar std

2. Implementando Traits da Biblioteca Padrão

Display e Debug

use std::fmt;

struct Ponto {
    x: i32,
    y: i32,
}

impl fmt::Display for Ponto {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

impl fmt::Debug for Ponto {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("Ponto")
            .field("x", &self.x)
            .field("y", &self.y)
            .finish()
    }
}

Clone e Copy

#[derive(Clone, Copy)]
struct Coordenada {
    x: f64,
    y: f64,
}

// Implementação manual quando necessário
struct Dados {
    valores: Vec<i32>,
}

impl Clone for Dados {
    fn clone(&self) -> Self {
        Dados {
            valores: self.valores.clone(),
        }
    }
}

PartialEq e Eq

struct Cor {
    r: u8,
    g: u8,
    b: u8,
}

impl PartialEq for Cor {
    fn eq(&self, other: &Self) -> bool {
        self.r == other.r && self.g == other.g && self.b == other.b
    }
}

impl Eq for Cor {} // Marca como equivalência total

3. Traits com Métodos Associados

Traits podem ter métodos obrigatórios e opcionais (com implementação default):

trait Animal {
    fn nome(&self) -> &str;

    // Método obrigatório
    fn fazer_som(&self) -> String;

    // Método opcional com implementação default
    fn descricao(&self) -> String {
        format!("{} faz '{}'", self.nome(), self.fazer_som())
    }
}

struct Cachorro {
    nome: String,
}

impl Animal for Cachorro {
    fn nome(&self) -> &str {
        &self.nome
    }

    fn fazer_som(&self) -> String {
        "Au au".to_string()
    }
    // descricao() usa a implementação default
}

4. Implementando Traits com Genéricos

Restrições com where clauses

trait Duplicavel {
    fn duplicar(&self) -> Self;
}

impl<T: Clone> Duplicavel for Vec<T> {
    fn duplicar(&self) -> Self {
        let mut resultado = self.clone();
        resultado.extend(self.iter().cloned());
        resultado
    }
}

Implementação condicional

trait Comparavel {
    fn eh_maior(&self, outro: &Self) -> bool;
}

impl<T: PartialOrd> Comparavel for T {
    fn eh_maior(&self, outro: &Self) -> bool {
        self > outro
    }
}

5. Traits com Tipos Associados

Tipos associados permitem definir um tipo dentro do trait que será especificado na implementação:

trait Conversor {
    type Entrada;
    type Saida;

    fn converter(&self, valor: Self::Entrada) -> Self::Saida;
}

struct Temperatura;

impl Conversor for Temperatura {
    type Entrada = f64;
    type Saida = f64;

    fn converter(&self, valor: f64) -> f64 {
        (valor - 32.0) * 5.0 / 9.0 // Fahrenheit para Celsius
    }
}

Exemplo prático: Iterator

struct Contador {
    max: u32,
    atual: u32,
}

impl Iterator for Contador {
    type Item = u32;

    fn next(&mut self) -> Option<Self::Item> {
        if self.atual < self.max {
            let valor = self.atual;
            self.atual += 1;
            Some(valor)
        } else {
            None
        }
    }
}

6. Sobrecarga de Operadores com Traits

use std::ops::{Add, Neg};

struct Vetor2D {
    x: f64,
    y: f64,
}

impl Add for Vetor2D {
    type Output = Vetor2D;

    fn add(self, other: Vetor2D) -> Vetor2D {
        Vetor2D {
            x: self.x + other.x,
            y: self.y + other.y,
        }
    }
}

impl Neg for Vetor2D {
    type Output = Vetor2D;

    fn neg(self) -> Vetor2D {
        Vetor2D {
            x: -self.x,
            y: -self.y,
        }
    }
}

Boas práticas: Mantenha a semântica esperada. Não implemente Add para subtração ou operações inconsistentes.

7. Traits e Lifetime Annotations

struct Texto<'a> {
    conteudo: &'a str,
}

impl<'a> std::fmt::Display for Texto<'a> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.conteudo)
    }
}

// Implementação condicional com lifetimes
impl<'a, T: std::fmt::Display + 'a> std::fmt::Display for &'a T {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        (**self).fmt(f)
    }
}

8. Padrões Avançados de Implementação

Newtype Pattern

Útil para implementar traits externos em tipos externos:

struct MeuVec(Vec<i32>);

impl std::fmt::Display for MeuVec {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "[{}]", self.0.iter().map(|x| x.to_string()).collect::<Vec<_>>().join(", "))
    }
}

Blanket Implementations

trait Mensagem {
    fn mensagem(&self) -> String;
}

// Implementa Mensagem para qualquer tipo que implemente Display
impl<T: std::fmt::Display> Mensagem for T {
    fn mensagem(&self) -> String {
        format!("Valor: {}", self)
    }
}

Combinação com derive e implementação manual

#[derive(Debug, Clone)]
struct Usuario {
    nome: String,
    email: String,
}

impl PartialEq for Usuario {
    fn eq(&self, other: &Self) -> bool {
        self.email == other.email // Compara apenas por email
    }
}

Conclusão

A implementação de traits em Rust oferece um sistema flexível e poderoso para definir comportamentos compartilhados. Dominar desde os fundamentos até padrões avançados como newtype pattern e blanket implementations permite criar código mais expressivo, reutilizável e seguro. A combinação de traits com genéricos, lifetimes e tipos associados forma a base para o polimorfismo em Rust, permitindo abstrações eficientes sem sacrificar performance.

Referências