Desafio Rust

Enum com derive e Display condicional

Enunciado

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.

Requisitos

  • O enum Shape deve ter as variantes Circle e Rectangle com os campos especificados.
  • Os traits Debug, Clone, PartialEq e Default devem ser derivados; Default deve retornar Circle { radius: 1.0 }.
  • Display deve ser implementado manualmente para formatar cada variante.
  • O programa deve demonstrar Default, Clone, PartialEq, Display e Debug com um vetor de formas.

Código inicial

use std::fmt;

// Defina o enum Shape e derive Debug, Clone, PartialEq, Default
// Implemente Default manualmente para Circle { radius: 1.0 }

// Implemente Display para Shape

fn main() {
    // Crie um vetor de formas
    // Clone o vetor
    // Compare elementos
    // Imprima tudo com Display e Debug
}

Saída esperada

Formas originais:
Círculo de raio 2.5
Retângulo de largura 3 e altura 4
Formas clonadas:
Círculo de raio 2.5
Retângulo de largura 3 e altura 4
Os vetores são iguais? true
Debug do primeiro clone: Circle { radius: 2.5 }
Debug do padrão: Circle { radius: 1.0 }
Ver dica

Para Default, implemente manualmente impl Default for Shape { fn default() -> Self { Shape::Circle { radius: 1.0 } } }. No Display, use match para tratar cada variante.

Mostrar solução
use std::fmt;

#[derive(Debug, Clone, PartialEq)]
enum Shape {
    Circle { radius: f64 },
    Rectangle { width: f64, height: f64 },
}

impl Default for Shape {
    fn default() -> Self {
        Shape::Circle { radius: 1.0 }
    }
}

impl fmt::Display for Shape {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Shape::Circle { radius } => write!(f, "Círculo de raio {}", radius),
            Shape::Rectangle { width, height } => write!(f, "Retângulo de largura {} e altura {}", width, height),
        }
    }
}

fn main() {
    let formas = vec![
        Shape::Circle { radius: 2.5 },
        Shape::Rectangle { width: 3.0, height: 4.0 },
    ];

    println!("Formas originais:");
    for forma in &formas {
        println!("{}", forma);
    }

    let clonadas = formas.clone();

    println!("Formas clonadas:");
    for forma in &clonadas {
        println!("{}", forma);
    }

    println!("Os vetores são iguais? {}", formas == clonadas);

    println!("Debug do primeiro clone: {:?}", clonadas[0]);
    println!("Debug do padrão: {:?}", Shape::default());
}

Passo a passo

  1. Definimos o enum Shape com as variantes Circle e Rectangle, cada uma com campos f64.
  2. Derivamos Debug, Clone e PartialEq, mas não Default, pois queremos um padrão personalizado.
  3. Implementamos Default manualmente para retornar Shape::Circle { radius: 1.0 }.
  4. Implementamos Display com um match que formata cada variante de acordo com o enunciado.
  5. No main, criamos um vetor formas com duas instâncias.
  6. Imprimimos as formas originais usando Display (laço for).
  7. Clonamos o vetor com .clone() e imprimimos as formas clonadas.
  8. Comparamos os vetores com == (funciona porque Shape deriva PartialEq).
  9. Imprimimos o Debug do primeiro clone e do valor padrão.

Por que funciona

O derive gera implementações para Debug, Clone e PartialEq porque todos os campos são f64, que já implementam esses traits. Default é implementado manualmente para escolher uma variante padrão. Display é manual para formatar cada variante de forma legível. O clone do vetor cria uma cópia profunda, e a comparação verifica igualdade campo a campo.

Erros comuns

  • Tentar derivar Default e obter a primeira variante com valores zero: se derivar, o padrão seria Circle { radius: 0.0 }, mas queremos 1.0. Solução: implementar manualmente.
  • Esquecer de derivar PartialEq e tentar comparar vetores com ==: erro de compilação. Solução: adicionar PartialEq ao derive.
  • No Display, não cobrir todas as variantes do match: o compilador acusa match não exaustivo. Solução: tratar todas as variantes.
  • Usar {} para imprimir Shape sem implementar Display: erro de compilação. Solução: implementar Display ou usar {:?}.

Outra forma de resolver

Se quiser que o padrão seja Rectangle { width: 0.0, height: 0.0 }, basta derivar Default e remover a implementação manual. No entanto, isso só funciona se a variante padrão for a primeira e todos os campos tiverem Default. Para maior controle, a implementação manual é preferível.

Saída esperada

Formas originais:
Círculo de raio 2.5
Retângulo de largura 3 e altura 4
Formas clonadas:
Círculo de raio 2.5
Retângulo de largura 3 e altura 4
Os vetores são iguais? true
Debug do primeiro clone: Circle { radius: 2.5 }
Debug do padrão: Circle { radius: 1.0 }