💻 Exemplos: Capítulo 10: Enums Ricos, Option, Result e Pattern Matching

Especialização em Sistemas com Rust • Demonstrações Práticas Compiláveis


🎯 Objetivo dos Exemplos

Explorar Tipos Algébricos de Dados (Algebraic Data Types) através de Enums com variantes contendo dados embutidos, eliminação de ponteiros nulos com Option<T>, tratamento de falhas com Result<T, E>, casamento de padrões exaustivo com match, e propagação de erros com o operador ?.


1. Código Fonte Completo (src/main.rs)

//! Demonstração de Enums Ricos, Option, Result e Pattern Matching Exaustivo

// Enum com variantes heterogêneas contendo diferentes estruturas de dados
#[derive(Debug)]
enum ComandoRede {
    Conectar { ip: String, porta: u16 },
    EnviarPacote(Vec<u8>),
    AjustarTimeout(u32),
    Desconectar,
}

// Enum customizado para representar códigos de erro do sistema
#[derive(Debug)]
enum ErroRede {
    PortaInvalida,
    PacoteVazio,
    ConexaoRecusada(String),
}

/// Função que processa comandos usando match exaustivo
fn despachar_comando(cmd: &ComandoRede) {
    match cmd {
        ComandoRede::Conectar { ip, porta } => {
            println!("  [REDE] Estabelecendo handshake com {}:{}...", ip, porta);
        }
        ComandoRede::EnviarPacote(bytes) => {
            println!("  [REDE] Transmitindo payload binário de {} bytes...", bytes.len());
        }
        ComandoRede::AjustarTimeout(ms) => {
            println!("  [REDE] Timeout reconfigurado para {} ms.", ms);
        }
        ComandoRede::Desconectar => {
            println!("  [REDE] Conexão encerrada graciosamente.");
        }
    }
}

/// Função que valida parâmetros retornando Result<T, ErroRede>
fn validar_e_montar_conexao(ip: &str, porta: u16) -> Result<ComandoRede, ErroRede> {
    if porta == 0 {
        return Err(ErroRede::PortaInvalida);
    }
    if ip == "127.0.0.99" {
        return Err(ErroRede::ConexaoRecusada(String::from("Host em quarentena")));
    }

    Ok(ComandoRede::Conectar {
        ip: String::from(ip),
        porta,
    })
}

/// Função que utiliza o operador '?' para propagar falhas instantaneamente
fn inicializar_subsistema() -> Result<(), ErroRede> {
    let cmd1 = validar_e_montar_conexao("10.0.0.1", 8080)?; // Se retornar Err, sai da função aqui!
    despachar_comando(&cmd1);

    let cmd2 = validar_e_montar_conexao("10.0.0.2", 443)?;
    despachar_comando(&cmd2);

    Ok(())
}

fn main() {
    println!("=== PATTERN MATCHING, OPTION E RESULT ===");

    // 1. Despacho polimórfico de comandos via Enum
    let comandos = [
        ComandoRede::Conectar { ip: String::from("192.168.1.1"), porta: 22 },
        ComandoRede::EnviarPacote(vec![0xAA, 0xBB, 0xCC, 0xDD]),
        ComandoRede::AjustarTimeout(3000),
        ComandoRede::Desconectar,
    ];

    println!("Executando fila de comandos de rede:");
    for c in &comandos {
        despachar_comando(c);
    }

    // 2. Manipulação de Option<T> (Eliminando Null Pointers)
    let usuarios_ativos: [Option<&str>; 3] = [Some("Alice"), None, Some("Roberto")];
    println!("\nProcessando usuários com Option:");
    for (i, usuario) in usuarios_ativos.iter().enumerate() {
        match usuario {
            Some(nome) => println!("  Slot {}: Usuário autenticado '{}'", i, nome),
            None => println!("  Slot {}: Vazio (Nenhum usuário conectado)", i),
        }
    }

    // 3. Sintaxe 'if let' para quando apenas uma variante interessa
    let configuracao_opcional: Option<u32> = Some(4096);
    if let Some(tamanho_buffer) = configuracao_opcional {
        println!("\nConfiguração detectada via 'if let': {} bytes de buffer", tamanho_buffer);
    }

    // 4. Executando pipeline com o operador '?'
    println!("\nIniciando subsistema com validação estrita:");
    match inicializar_subsistema() {
        Ok(_) => println!("Subsistema de rede iniciado com 100% de sucesso!"),
        Err(e) => println!("Falha crítica de inicialização: {:?}", e),
    }

    // 5. Testando caso de erro com Result
    println!("\nTestando tentativa de conexão com porta zero:");
    let conexao_invalida = validar_e_montar_conexao("192.168.1.1", 0);
    match conexao_invalida {
        Ok(_) => println!("Conexão aceita inesperadamente!"),
        Err(e) => println!("Erro capturado com sucesso pelo sistema: {:?}", e),
    }
}

2. Saída Esperada no Terminal

=== PATTERN MATCHING, OPTION E RESULT ===
Executando fila de comandos de rede:
  [REDE] Estabelecendo handshake com 192.168.1.1:22...
  [REDE] Transmitindo payload binário de 4 bytes...
  [REDE] Timeout reconfigurado para 3000 ms.
  [REDE] Conexão encerrada graciosamente.

Processando usuários com Option:
  Slot 0: Usuário autenticado 'Alice'
  Slot 1: Vazio (Nenhum usuário conectado)
  Slot 2: Usuário autenticado 'Roberto'

Configuração detectada via 'if let': 4096 bytes de buffer

Iniciando subsistema com validação estrita:
  [REDE] Estabelecendo handshake com 10.0.0.1:8080...
  [REDE] Estabelecendo handshake com 10.0.0.2:443...
Subsistema de rede iniciado com 100% de sucesso!

Testando tentativa de conexão com porta zero:
Erro capturado com sucesso pelo sistema: PortaInvalida