Menu
Coddy logo textTech

Vetores de Traits

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

Você viu como Box<dyn Trait> permite que uma única variável contenha tipos diferentes. O verdadeiro poder surge quando você combina isso com coleções: armazenando vários tipos diferentes em um único vetor.

Um vetor comum exige que todos os elementos sejam do mesmo tipo. Você não pode ter um Vec<Dog> que também contenha gatos. Mas, com objetos de trait, você pode criar um vetor que contenha qualquer coisa que implemente um trait compartilhado:

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

struct Dog;
struct Cat;
struct Bird;

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

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

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

fn main() {
    let animals: Vec<Box<dyn Speak>> = vec![
        Box::new(Dog),
        Box::new(Cat),
        Box::new(Bird),
    ];
}

O tipo Vec<Box<dyn Speak>> significa "um vetor de objetos de trait em caixas." Cada elemento é um Box que aponta para algo que implementa Speak: os tipos reais podem ser diferentes. Você envolve cada valor com Box::new() ao adicioná-lo ao vetor.

Este padrão é essencial para criar sistemas flexíveis nos quais você precisa gerenciar coleções de objetos relacionados, mas diferentes, como componentes de UI, entidades de jogos ou sistemas de plugins.

challenge icon

Desafio

Fácil

Vamos criar um sistema de notificações capaz de lidar com diferentes tipos de alertas! Você criará uma coleção que armazena vários tipos de notificações, e-mails, mensagens SMS e notificações push, todos em um único vetor usando objetos de trait.

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

  • notifications.rs: defina um trait público Notify com um método send que recebe &self e retorna uma String descrevendo a notificação que está sendo enviada. Em seguida, crie três structs públicas:
    • Email: com um campo público recipient (String). Seu send deve retornar Email to: {recipient}
    • Sms: com um campo público phone (String). Seu send deve retornar SMS to: {phone}
    • Push: com um campo público device (String). Seu send deve retornar Push to: {device}
  • main.rs: importe seu módulo de notificações e crie um vetor do tipo Vec<Box<dyn Notify>> que contenha os três tipos de notificações. Use as entradas fornecidas para criar uma notificação de cada tipo, adicione-as ao vetor na ordem (Email, Sms, Push) e, em seguida, imprima o resultado da chamada de send() no primeiro elemento do vetor.

O conceito principal aqui é que, apesar de Email, Sms e Push serem structs completamente diferentes, todos podem coexistir no mesmo vetor porque compartilham o trait Notify. Cada elemento é encapsulado com Box::new() para criar o objeto de trait.

Sua saída deve mostrar a primeira notificação:

Email to: {recipient}

Por exemplo, com as entradas alice@example.com, 555-1234 e iPhone-12:

Email to: alice@example.com

Você receberá três entradas: o destinatário do e-mail, o número de telefone e o nome do dispositivo.

Experimente você mesmo

mod notifications;

use notifications::{Notify, Email, Sms, Push};

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

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

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

    // TODO: Criar um Vec<Box<dyn Notify>> para armazenar diferentes tipos de notificação
    // TODO: Criar instâncias de Email, Sms e Push usando as entradas
    // TODO: Adicioná-los ao vetor na ordem (Email, Sms, Push) usando Box::new()
    // TODO: Imprimir o resultado de chamar send() no primeiro elemento
}
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