Menu
Coddy logo textTech

Despacho Dinâmico

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

Quando você usa genéricos com limites de trait, como <T: Summary>, Rust determina o tipo exato em tempo de compilação. Isso é chamado de despacho estático: o compilador gera código especializado para cada tipo concreto que você usa. É rápido, mas há uma limitação: uma variável só pode conter um tipo específico.

E se você precisar de uma única variável que possa conter tipos diferentes em tempo de execução? É aqui que entram os objetos de trait. Usando Box<dyn Trait>, você pode armazenar qualquer tipo que implemente o trait:

trait Speak {
    fn speak(&self) -> String;
}

struct Dog;
struct Cat;

impl Speak for Dog {
    fn speak(&self) -> String { String::from("Woof!") }
}

impl Speak for Cat {
    fn speak(&self) -> String { String::from("Meow!") }
}

fn main() {
    let animal: Box<dyn Speak> = Box::new(Dog);
    println!("{}", animal.speak());  // "Woof!"
    
    let animal: Box<dyn Speak> = Box::new(Cat);
    println!("{}", animal.speak());  // "Meow!"
}

A palavra-chave dyn indica despacho dinâmico: o Rust determina em tempo de execução qual método chamar, em vez de fazê-lo em tempo de compilação. O Box é necessário porque objetos de trait não têm um tamanho conhecido; Box fornece um ponteiro com tamanho fixo.

Pense desta forma: os genéricos dizem "trabalho com o tipo T", enquanto os objetos de trait dizem "trabalho com qualquer coisa que possa fazer isto". A compensação é um pequeno custo em tempo de execução pela flexibilidade de lidar com tipos diferentes por meio da mesma variável.

challenge icon

Desafio

Fácil

Vamos criar um sistema de aluguel de veículos que demonstra o poder do despacho dinâmico! Você criará um trait que define o que qualquer veículo alugável pode fazer e, em seguida, usará Box<dyn Trait> para armazenar diferentes tipos de veículos na mesma variável.

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

  • vehicle.rs: Defina um trait público Rentable com um método rental_info que recebe &self e retorna uma String. Em seguida, crie duas structs públicas:
    • Car: com um campo público model (String). Seu rental_info deve retornar Car: {model}
    • Bike: com um campo público brand (String). Seu rental_info deve retornar Bike: {brand}
  • main.rs: Inclua seu módulo de veículos e use as entradas para demonstrar o despacho dinâmico. Crie uma variável Box<dyn Rentable> que primeiro contenha um Car, imprima suas informações de aluguel, depois reatribua a mesma variável para conter um Bike e imprima novamente suas informações de aluguel.

A mágica aqui é que uma única variável do tipo Box<dyn Rentable> pode conter tanto um Car quanto um Bike: o Rust descobre qual método rental_info chamar em tempo de execução. Isso é o despacho dinâmico em ação!

Sua saída deve mostrar as informações dos dois veículos:

Car: {model}
Bike: {brand}

Por exemplo, com as entradas Tesla Model 3 e Trek:

Car: Tesla Model 3
Bike: Trek

Você receberá duas entradas: o modelo do carro e a marca da bicicleta.

Experimente você mesmo

mod vehicle;

use vehicle::{Rentable, Car, Bike};

fn main() {
    // Ler entrada
    let mut car_model = String::new();
    std::io::stdin().read_line(&mut car_model).expect("Failed to read line");
    let car_model = car_model.trim().to_string();
    
    let mut bike_brand = String::new();
    std::io::stdin().read_line(&mut bike_brand).expect("Failed to read line");
    let bike_brand = bike_brand.trim().to_string();
    
    // TODO: Crie uma variável Box<dyn Rentable> que contenha um Car
    // Imprima suas informações de aluguel usando o método rental_info()
    
    // TODO: Reatribua a mesma variável para conter um Bike
    // Imprima suas informações de aluguel novamente
    
}
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