- Rust 100%
| .woodpecker | ||
| src | ||
| tests | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| LICENSE | ||
| README.md | ||
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
returne 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
- Implementar
enviar_sinal: Retorne true se o código for maior que 0 (sinal válido transmitido) - Implementar
calcular_trajetoria: Calcule a distância euclidiana entre dois pontos usando a fórmula √((x₂-x₁)² + (y₂-y₁)²) - Implementar
processar_comando: Se comando for "STATUS", retorne Ok com "Sistema operacional"; para outros comandos, retorne Err com "Comando desconhecido" - Implementar
validar_telemetria: Retorne true se o slice não estiver vazio e todos os valores forem não-negativos - Implementar
gerar_relatorio_status: Retorne string formatada: "Módulo [nome]: [ATIVO/INATIVO]" baseado no booleano status - 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
returnapenas 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 índiceponto.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)eErr(E)— usematchou métodos como.map_err()