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

Rust Tipos Intermediário

derive e traits comuns

Em Rust, derive é um atributo que gera automaticamente implementações de certos traits para suas structs e enums. Isso evita escrever código repetitivo e garante que seus tipos se comportem como os tipos da biblioteca padrão. Os traits mais comuns de derivar são Debug, Clone, PartialEq, Eq e Default.

Cada trait derivado adiciona uma capacidade específica: Debug permite formatar com {:?}, Clone cria cópias explícitas, PartialEq e Eq habilitam comparações com == e !=, e Default fornece um valor padrão. O trait Display, por outro lado, não pode ser derivado, pois exige uma formatação personalizada; você deve implementá-lo manualmente.

Neste card, vamos explorar como usar derive para esses traits comuns e quando é necessário implementar Display à mão. Também veremos como o compilador impõe restrições, como a necessidade de todos os campos também implementarem o trait para que o derive funcione.

Pontos-chave

  • #[derive(Debug, Clone, PartialEq, Eq, Default)] gera implementações automáticas para a maioria dos traits comuns.
  • Display não pode ser derivado; requer implementação manual do método fmt.
  • PartialEq permite comparar com ==, enquanto Eq é uma marcação que indica que a igualdade é reflexiva.
  • Default fornece um valor inicial; Clone permite duplicar explicitamente com .clone().
derive_traits.rs
use std::fmt;

// Deriva vários traits comuns para a struct
#[derive(Debug, Clone, PartialEq, Eq, Default)]
struct Point {
    x: i32,
    y: i32,
}

// Display não pode ser derivado, então implementamos manualmente
impl fmt::Display for Point {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.x, self.y)
    }
}

fn main() {
    // Debug: formatação com {:?}
    let p1 = Point { x: 1, y: 2 };
    println!("Debug: {:?}", p1);

    // Clone: cria uma cópia explícita
    let p2 = p1.clone();
    println!("Clone: {:?}", p2);

    // PartialEq: comparação com ==
    println!("PartialEq: {}", p1 == p2);

    // Default: valor padrão (0, 0)
    let p3 = Point::default();
    println!("Default: {}", p3);

    // Display: formatação personalizada
    println!("Display: {}", p1);
}

Exercícios

  1. 1
    Fácil

    Derivando Debug e PartialEq

    Crie uma struct Person com os campos name: String e age: u32. Derive Debug e PartialEq para ela. No main, crie duas instâncias, imprima-as com {:?} e compare-as com ==.

    Resolver
  2. 2
    Médio

    Default e Display personalizado

    Crie uma struct Rectangle com campos width: f64 e height: f64. Derive Debug, Clone e Default. Implemente manualmente Display para exibir o retângulo no formato Retângulo: largura x altura. No main, crie um retângulo padrão, clone-o, modifique o clone e imprima ambos usando Display e Debug.

    Resolver
  3. 3
    Desafio

    Enum com derive e Display condicional

    Crie um enum Shape com variantes Circle { radius: f64 } e Rectangle { width: f64, height: f64 }. Derive Debug, Clone, PartialEq e Default (a variante padrão deve ser Circle { radius: 1.0 }). Implemente Display para Shape, mostrando "Círculo de raio X" ou "Retângulo de largura X e altura Y". No main, crie um vetor com várias formas, clone-o, compare elementos e imprima todos usando Display e Debug.

    Resolver

Continue estudando