Menu
Coddy logo textTech

Iterando Objetos Trait

Parte da seção Programação Orientada a Objetos do Journey de Rust da Coddy. Lição 47 de 61.

Agora que você pode armazenar diferentes tipos em um Vec<Box<dyn Trait>>, o próximo passo é processar essa coleção. Iterar sobre objetos de trait funciona exatamente como iterar sobre qualquer vetor. Você percorre cada elemento e chama os métodos definidos pelo trait.

trait Shape {
    fn area(&self) -> f64;
}

struct Circle { radius: f64 }
struct Rectangle { width: f64, height: f64 }

impl Shape for Circle {
    fn area(&self) -> f64 { 3.14159 * self.radius * self.radius }
}

impl Shape for Rectangle {
    fn area(&self) -> f64 { self.width * self.height }
}

fn main() {
    let shapes: Vec<Box<dyn Shape>> = vec![
        Box::new(Circle { radius: 2.0 }),
        Box::new(Rectangle { width: 3.0, height: 4.0 }),
        Box::new(Circle { radius: 1.0 }),
    ];

    for shape in &shapes {
        println!("Area: {}", shape.area());
    }
}

Ao iterar com for shape in &shapes, cada shape é uma referência a um Box<dyn Shape>. Você pode chamar diretamente qualquer método do trait Shape: o Rust lida automaticamente com o despacho dinâmico, chamando a implementação correta para cada tipo concreto.

Esse padrão é poderoso para agregar resultados. Você poderia somar todas as áreas, filtrar formas por tamanho ou transformar a coleção. A principal ideia é que, uma vez que os itens estejam em uma coleção de objetos de trait, você interage com eles exclusivamente por meio da interface do trait, independentemente de seus tipos subjacentes.

challenge icon

Desafio

Fácil

Vamos criar uma calculadora de preços para um carrinho de compras que pode conter diferentes tipos de itens! Você criará um sistema no qual produtos e serviços, cada um com uma lógica de preços diferente, possam ser armazenados juntos e processados para calcular um preço total.

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

  • items.rs: Defina um trait público Priceable com um método price que recebe &self e retorna um f64. Em seguida, crie duas structs públicas:
    • Product: com os campos públicos name (String) e cost (f64). Seu price deve simplesmente retornar o cost.
    • Service: com os campos públicos name (String), hourly_rate (f64) e hours (f64). Seu price deve retornar hourly_rate * hours.
  • main.rs: Importe seu módulo de itens e crie um vetor do tipo Vec<Box<dyn Priceable>>. Use as entradas para criar um Product e um Service, adicione-os ao seu vetor e, em seguida, itere pela coleção para calcular e imprimir o preço total de todos os itens.

O poder dos objetos de trait se destaca aqui. Seu código de iteração não precisa saber se está processando um Product ou um Service. Ele simplesmente chama price() em cada item, e o Rust direciona automaticamente para a implementação correta.

Sua saída deve exibir o preço total com duas casas decimais:

Total: ${total}

Por exemplo, com as entradas Laptop, 999.99, Consulting, 150.0 e 3.0:

Total: $1449.99

E com as entradas Book, 29.99, Tutoring, 50.0 e 2.0:

Total: $129.99

Você receberá cinco entradas: o nome do produto, o custo do produto, o nome do serviço, a tarifa por hora e as horas trabalhadas (analise os valores numéricos como f64).

Experimente você mesmo

mod items;

use items::{Priceable, Product, Service};

fn main() {
    // Ler entradas
    let mut product_name = String::new();
    std::io::stdin().read_line(&mut product_name).expect("Failed to read line");
    let product_name = product_name.trim().to_string();

    let mut product_cost = String::new();
    std::io::stdin().read_line(&mut product_cost).expect("Failed to read line");
    let product_cost: f64 = product_cost.trim().parse().expect("Failed to parse");

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

    let mut hourly_rate = String::new();
    std::io::stdin().read_line(&mut hourly_rate).expect("Failed to read line");
    let hourly_rate: f64 = hourly_rate.trim().parse().expect("Failed to parse");

    let mut hours = String::new();
    std::io::stdin().read_line(&mut hours).expect("Failed to read line");
    let hours: f64 = hours.trim().parse().expect("Failed to parse");

    // TODO: Crie um Product usando product_name e product_cost

    // TODO: Crie um Service usando service_name, hourly_rate e hours

    // TODO: Crie um Vec<Box<dyn Priceable>> e adicione ambos os itens a ele

    // TODO: Itere pelo vetor e calcule o preço total

    // TODO: Imprima o total com uma casa decimal
    // Formato: Total: ${total:.1}
}
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 Programação Orientada a Objetos

Pratique por conta própria: Compilador de Rust online