No description
Find a file
2026-08-11 14:38:23 +02:00
.woodpecker fix: content audit corrections + CI migration to woodpecker + MSRV 1.85 2026-08-11 09:49:11 +02:00
src fix: content audit corrections + CI migration to woodpecker + MSRV 1.85 2026-08-11 09:49:11 +02:00
tests fix(009): pedagogical MINOR fixes (forward-refs, test strength, contract docs) 2026-08-11 14:38:23 +02:00
.gitignore Initial commit 2026-08-07 09:43:01 +00:00
Cargo.lock initial content 2026-08-07 11:43:33 +02:00
Cargo.toml fix: content audit corrections + CI migration to woodpecker + MSRV 1.85 2026-08-11 09:49:11 +02:00
LICENSE Initial commit 2026-08-07 09:43:01 +00:00
README.md fix: content audit corrections + CI migration to woodpecker + MSRV 1.85 2026-08-11 09:49:11 +02:00

Lição 9: Protocolos de Comunicação

Narrativa

O sistema de comunicação é a espinha dorsal de qualquer mecha. Sem protocolos claros, até o piloto mais habilidoso se torna inoperante. Na Academia Æther, você aprenderá a estabelecer esses protocolos — uma linguagem estruturada onde cada função representa um comando específico que a mecha compreende.

Imagine-se na cabine, diante de dezenas de controles. Cada botão ativa uma função; cada função executa uma rotina. Quando você envia um sinal de emergência, está chamando uma função. Quando calcula uma trajetória de fuga, está invocando outra. Entender como definir, chamar e retornar dessas funções é o que separa um operador de um verdadeiro Piloto.

Conceito

Funções em Rust são blocos de código nomeados que realizam uma tarefa específica. Elas são a fundação da organização de código e reuso. Uma função é definida com a palavra-chave fn, seguida por um nome, parâmetros opcionais entre parênteses, e um tipo de retorno opcional:

fn nome_funcao(parametro: Tipo) -> TipoRetorno {
    // corpo da função
}

Parâmetros são valores de entrada que a função recebe. Cada parâmetro deve ter um tipo anotado explicitamente — Rust não inferirá tipos de parâmetros. Você pode ter múltiplos parâmetros separados por vírgulas.

Retorno especifica o tipo de valor que a função devolve. Use -> seguido do tipo. Se não houver retorno explícito, a função retorna o tipo unit (), que representa "nada" (similar a void em outras linguagens, mas é um tipo real).

Statements vs Expressions: Esta distinção é crucial em Rust. Um statement realiza uma ação mas não retorna valor (ex: let x = 5;). Uma expression produz um valor (ex: 5 + 3, ou um bloco { let x = 5; x + 1 }). O valor final de uma função é a última expression (sem ponto-e-vírgula), ou você pode usar return para retorno antecipado.

Requisitos

  • Entrada: Diversos tipos de dados representando comandos do mecha
  • Processamento: Executar funções com diferentes assinaturas e tipos de retorno
  • Saída: Resultados variados (booleanos, numéricos, mensagens, erros)

Design de Dados

Esta lição explora a versatilidade das funções em Rust através de protocolos de comunicação mecha:

// Funções de comunicação com diferentes assinaturas
pub fn enviar_sinal(codigo: u8) -> bool;
pub fn calcular_trajetoria(inicio: (f64, f64), fim: (f64, f64)) -> f64;
pub fn processar_comando(comando: &str) -> Result<String, &str>;
pub fn validar_telemetria(dados: &[i32]) -> bool;
pub fn gerar_relatorio_status(modulo: &str, status: bool) -> String;
pub fn combinar_leituras(a: f64, b: f64, c: f64) -> f64;

Cada função demonstra diferentes padrões: parâmetros simples, tuplas, slices, referências de string, múltiplos parâmetros, e tipos de retorno variados.

Diagrama Conceitual

flowchart TD
    A[Chamada de Função] --> B{Parâmetros}
    B -->|u8| C[enviar_sinal]
    B -->|Tuplas| D[calcular_trajetoria]
    B -->|&str| E[processar_comando]
    B -->|Slice| F[validar_telemetria]
    B -->|Múltiplos| G[gerar_relatorio_status]
    B -->|Três f64| H[combinar_leituras]
    C --> I[Retorno bool]
    D --> J[Retorno f64]
    E --> K[Result<String, &str>]
    F --> L[Retorno bool]
    G --> M[Retorno String]
    H --> N[Retorno f64]
    I --> O[Execução Completa]
    J --> O
    K --> O
    L --> O
    M --> O
    N --> O

Funções e Módulos

//! Lição 9: Protocolos de Comunicação
//!
//! Estabelecendo linguagem de comandos entre piloto e mecha.

/// Envia um sinal de comunicação com o código especificado
/// Retorna true se o sinal foi transmitido com sucesso
pub fn enviar_sinal(codigo: u8) -> bool;

/// Calcula a distância euclidiana entre dois pontos de coordenadas
/// Útil para planejamento de trajetória da mecha
pub fn calcular_trajetoria(inicio: (f64, f64), fim: (f64, f64)) -> f64;

/// Processa um comando de texto e retorna resposta ou erro
/// Demonstra uso de Result para operações que podem falhar
pub fn processar_comando(comando: &str) -> Result<String, &str>;

/// Valida se os dados de telemetria estão dentro dos parâmetros aceitáveis
/// Recebe um slice de leituras e verifica consistência
pub fn validar_telemetria(dados: &[i32]) -> bool;

/// Gera uma mensagem de relatório formatada sobre o status de um módulo
/// Combina múltiplos parâmetros em uma string descritiva
pub fn gerar_relatorio_status(modulo: &str, status: bool) -> String;

/// Combina três leituras de sensores em sua média aritmética
/// Demonstra função com múltiplos parâmetros do mesmo tipo
pub fn combinar_leituras(a: f64, b: f64, c: f64) -> f64;

Exemplo do Conceito

// Função simples com parâmetro e retorno booleano
fn verificar_combustivel(nivel: u8) -> bool {
    nivel > 20 // expression implícita — sem ponto-e-vírgula
}

// Função com múltiplos parâmetros e retorno numérico
fn calcular_velocidade(distancia: f64, tempo: f64) -> f64 {
    if tempo == 0.0 {
        return 0.0; // early return explícito
    }
    distancia / tempo // expression final
}

// Função que retorna Result — demonstra tratamento de erro
fn parse_coordenada(entrada: &str) -> Result<f64, &str> {
    match entrada.parse::<f64>() {
        Ok(valor) => Ok(valor),
        Err(_) => Err("Coordenada inválida"),
    }
}

// Função com side-effect (impressão) — retorna unit ()
fn registrar_log(mensagem: &str) {
    println!("[LOG] {}", mensagem);
    // não há retorno explícito — retorna () implicitamente
}

// Função recebendo slice — trabalha com coleções de tamanho variável
fn media_leituras(valores: &[i32]) -> f64 {
    if valores.is_empty() {
        return 0.0;
    }
    let soma: i32 = valores.iter().sum();
    soma as f64 / valores.len() as f64
}

Explicação:

  • Linha 2-4: Função com expression implícita — o valor da última linha sem ; é retornado
  • Linha 7-12: Demonstração de early return com return e expression final
  • Linha 15-19: Result como tipo de retorno para operações que podem falhar
  • Linha 22-25: Função sem retorno explícito — retorna unit ()
  • Linha 28-33: Slice como parâmetro permite receber arrays ou vetores de qualquer tamanho

Missão

  1. Implementar enviar_sinal: Retorne true se o código for maior que 0 (sinal válido transmitido)
  2. Implementar calcular_trajetoria: Calcule a distância euclidiana entre dois pontos usando a fórmula √((x₂-x₁)² + (y₂-y₁)²)
  3. Implementar processar_comando: Se comando for "STATUS", retorne Ok com "Sistema operacional"; para outros comandos, retorne Err com "Comando desconhecido"
  4. Implementar validar_telemetria: Retorne true se o slice não estiver vazio e todos os valores forem não-negativos
  5. Implementar gerar_relatorio_status: Retorne string formatada: "Módulo [nome]: [ATIVO/INATIVO]" baseado no booleano status
  6. Implementar combinar_leituras: Retorne a média dos três valores (a + b + c) / 3.0

Diagrama de Fluxo da Missão

flowchart TD
    A[Tarefa: Protocolos de Comunicação] --> B[Implementar enviar_sinal]
    B --> C[Implementar calcular_trajetoria]
    C --> D[Implementar processar_comando]
    D --> E[Implementar validar_telemetria]
    E --> F[Implementar gerar_relatorio_status]
    F --> G[Implementar combinar_leituras]
    G --> H[Testes verificam]
    H --> I{Clippy limpo?}
    I -->|Sim| J[Concluído]
    I -->|Não| K[Corrigir warnings] --> H

Como Executar

# Executar testes
cargo test

# Verificar lint
cargo clippy -- -D warnings

# Formatar código
cargo fmt --check

Dicas

  • Lembre-se: a última expression sem ; é o valor de retorno implícito
  • Use return apenas para early returns (sair da função antes do final)
  • O tipo unit () é retornado quando você não especifica outro tipo de retorno
  • Tuplas são desestruturáveis: let (x, y) = ponto; ou acesse por índice ponto.0
  • Slices (&[T]) têm métodos úteis como .is_empty() e .iter()
  • Para calcular raiz quadrada, use .sqrt() em valores f64 (ex: valor.sqrt())
  • Result é um enum com variantes Ok(T) e Err(E) — use match ou métodos como .map_err()