Capítulo 03: Controle de Fluxo: if/else, loop, while e for
Capítulo 03: Controle de Fluxo: if/else, loop, while e for
Especialização em Sistemas com Rust • Rust 2021 Edition • Ownership, Concorrência Segura e Sistemas de Alta Performance
🗺️ Mapa Conceitual de Estruturas de Decisão e Laços de Repetição
flowchart TD
Fluxo["Controle de Fluxo em Rust (Expressões Avaliadas)"] --> Ramificacao["Decisão Condicional"]
Fluxo --> Repeticao["Laços de Repetição"]
subgraph RAMIFICACAO_DETALHE["Decisão: if / else if / else"]
IfExpr["if condicao { exp1 } else { exp2 }"]
TipagemRamos["Ramos Devem Retornar Exatamente o Mesmo Tipo T"]
ZeroTernario["Dispensa Operador Ternário (? :) de C/JS"]
end
subgraph REPETICAO_DETALHE["Mecanismos de Repetição"]
LoopIncondicional["loop: Loop Infinito com Retorno 'break valor'"]
LabeledLoops["'label: Rótulos para Interromper Laços Aninhados"]
WhileCond["while condicao { ... }: Loop Condicional"]
ForIter["for item in iterador: Seguro contra 'Off-by-One' e OOB"]
end
Ramificacao --- RAMIFICACAO_DETALHE
Repeticao --- REPETICAO_DETALHE
style Fluxo fill:#e1f5fe,stroke:#03a9f4,stroke-width:2px
style Ramificacao fill:#fff3e0,stroke:#ff9800,stroke-width:2px
style Repeticao fill:#ede7f6,stroke:#7e57c2,stroke-width:2px
style LoopIncondicional fill:#e8f5e9,stroke:#4caf50,stroke-width:2px
🏛️ 1. O Paradigma de Expressões no Controle de Fluxo
Em linguagens como C, C++, Java e JavaScript, estruturas como if/else e laços de repetição são declarações (statements), ou seja, blocos de código que executam ações imperativas mas não produzem um valor de saída direto. Para atribuir um resultado condicional, essas linguagens recorrem a operadores ternários (cond ? a : b) ou mutabilidade de variáveis externas.
No Rust, quase tudo é uma expressão (expression):
- O bloco
if/elseretorna um valor diretamente para ser atribuído a uma constante ou variável. - O compilador verifica se todos os ramos possíveis retornam rigorosamente o mesmo tipo de dado.
- Não existe operador ternário em Rust porque o próprio
if/elsejá cumpre essa função com sintaxe limpa e tipagem estrita.
⚙️ 2. A Estrutura Condicional if/else como Expressão
Veja como inicializar variáveis imutáveis com base em condições de negócio sem recorrer a mut:
let pressao_caldeira_psi = 142.5;
// Atribuição direta do resultado da expressão if/else
let estado_valvula: &str = if pressao_caldeira_psi > 150.0 {
"ABERTURA_EMERGENCIA"
} else if pressao_caldeira_psi > 120.0 {
"ALIVIO_PARCIAL"
} else {
"FECHADA"
};
println!("Comando enviado à válvula: {}", estado_valvula);
2.1 Garantia de Consistência de Tipos entre Ramos
Se um ramo retornar um inteiro e outro retornar uma string, o compilador rejeitará o código com o erro E0308: if and else have incompatible types. Essa restrição impede estados ambíguos de memória.
🔄 3. Os Três Laços de Repetição: loop, while e for
3.1 loop: Laço Infinito com Retorno de Valor pelo break
O comando loop instrui o compilador a gerar um laço sem condição de parada inicial. Ele é ideal para loops de eventos de polling, servidores de rede e rotinas de retentativa (retries).
Além disso, o break pode carregar um valor que se torna o resultado da expressão:
let mut contador_retries = 0;
let conexao_id: u32 = loop {
contador_retries += 1;
if tentar_handshake() {
// break com expressão: define o valor final de 'conexao_id'
break contador_retries * 1024;
}
if contador_retries >= 5 {
break 0; // Código de falha
}
};
3.2 Rótulos de Loop (Loop Labels) para Laços Aninhados
Quando se processam matrizes multidimensionais ou tabelas de dados aninhadas, interromper o laço externo a partir do laço interno costumava exigir flags booleanas auxiliares. O Rust resolve isso com rótulos identificados por apóstrofo ('nome):
'busca_matriz: for x in 0..10 {
for y in 0..10 {
if matriz[x][y] == VALOR_CRITICO {
println!("Elemento encontrado em ({}, {}). Encerrando busca total.", x, y);
break 'busca_matriz; // Interrompe o laço externo identificado
}
}
}
3.3 while: Repetição Condicional
Executa o bloco enquanto a condição for verdadeira. Se a condição for falsa na primeira avaliação, o bloco não executa nenhuma vez:
let mut bateria_pct = 100;
while bateria_pct > 15 {
executar_ciclo_drone();
bateria_pct -= 5;
}
println!("Bateria baixa. Iniciando pouso automático.");
3.4 for: A Maneira Idiomática e Segura de Iterar
Em Rust, você quase nunca deve usar while ou contadores manuais com índices para percorrer coleções. O laço for consome iteradores nativos, eliminando completamente erros de Off-by-One e checagens de limite em tempo de execução (Bounds Checking Elimination):
// 1. Ranges exclusivos [0, 5) -> 0 a 4
for i in 0..5 {
println!("Índice: {}", i);
}
// 2. Ranges inclusivos [1, 5] -> 1 a 5
for segundo in 1..=5 {
println!("Segundo: {}", segundo);
}
// 3. Iterador reverso
for contagem in (1..=3).rev() {
println!("{}...", contagem);
}
// 4. Iteração direta sobre coleções sem risco de IndexOutOfBounds
let sensores = ["TEMP_EXT", "HUMID_01", "BAROM_02"];
for sensor in sensores {
println!("Lendo sensor: {}", sensor);
}
⚖️ 4. Matriz Comparativa: loop vs while vs for
| Característica | loop |
while |
for |
|---|---|---|---|
| Condição Prévia | Nenhuma (incondicional) | Avaliada antes de cada ciclo | Baseada em iterador |
Retorno de Valor via break |
SIM (break valor;) |
Não (retorna ()) |
Não (retorna ()) |
| Garantia de Término | Depende de break explícito |
Depende de condição mutável | Garante término sobre coleções finitas |
| Caso de Uso Ideal | Polling, Retries, Servidores | Condições com múltiplos fatores | Percorrer listas, vetores e ranges numéricos |
⚠️ 5. Armadilhas Comuns e Mensagens do Compilador
- Esquecer o Ramo
elsequandoifé Expressão de Atribuição:let status = if ativo { "ON" }; // ERRO: `if` may be missing an `else` clauseExplicação: Se a condição for falsa, a variável ficaria sem valor definido, o que é expressamente proibido pela segurança do Rust. Todo
ifde atribuição deve ter obrigatoriamente umelse. - Usar
for i in 0..vetor.len():- Anti-Pattern: Acessar
vetor[i]dentro do loop força o compilador a checar os limites do array a cada iteração. - Correção Idiomática: Use
for item in &vetoroufor (i, item) in vetor.iter().enumerate().
- Anti-Pattern: Acessar
🛡️ 6. Boas Práticas de Engenharia em Rust
- Imutabilidade Sempre: Prefira inicializar valores com
let x = if ... else ...;a declararlet mut x;e preenchê-la dentro de um bloco condicional imperativo. - Aproveite a Eliminação de Bounds Check: Ao usar laços
forsobre iteradores, o compilador do Rust remove instruções assembly de verificação de limites do código final gerado, tornando seu loop tão ou mais rápido que código C otimizado.
📋 7. Cheat-Sheet: Resumo Executivo
// if/else como expressão
let modo = if debug { "VERBOSE" } else { "SILENT" };
// loop com valor
let res = loop { if pronto() { break 42; } };
// Laço rotulado
'externo: for x in 0..5 { break 'externo; }
// Range inclusivo e reverso
for n in (1..=10).rev() { /* ... */ }