Loops em Rust
O Rust tem três jeitos de repetir código: loop, while e for. Esta página trata do loop, o mais simples e direto dos três: ele repete para sempre, até você mandar parar.
Um loop básico
Seção intitulada “Um loop básico”fn main() { let mut count = 0;
loop { count += 1; println!("{count}");
if count == 3 { break; } }}Saída:
123Sozinho, o loop nunca para: quem o encerra é o break. Sem aquele if count == 3 { break; }, este programa ficaria imprimindo para sempre.
Retornando um valor de um loop
Seção intitulada “Retornando um valor de um loop”Aqui está algo que o loop consegue fazer e o while e o for não: você pode colocar um valor depois do break, e ele vira o resultado do loop inteiro:
fn main() { let mut count = 0;
let result = loop { count += 1; if count == 10 { break count * 2; // para e devolve um valor } };
println!("{result}");}Saída:
20Isso é útil em situações como “continue tentando até dar certo e depois me entregue o resultado”. Você vai encontrar esse padrão em código de verdade mais vezes do que imagina.
Repare no ponto e vírgula depois do } que fecha o loop. O loop { ... } inteiro é o lado direito de let result = ...;, então a instrução let precisa do seu ; no final, igualzinho a let x = 5;.
Por que loop em vez de while true?
Seção intitulada “Por que loop em vez de while true?”Se você vem de outra linguagem, talvez escreva um loop infinito como while true { ... }. Isso funciona em Rust, mas o compilador avisa:
warning: denote infinite loops with `loop { ... }` --> src/main.rs:5:5 |5 | while true { | ^^^^^^^^^^ help: use `loop`O aviso sugere marcar loops infinitos com loop { ... }. E não é só uma questão de estilo. O Rust sabe que o corpo de um loop sempre é executado e que a única saída é um break. Ele não assume isso para o while true, porque não olha o valor da condição. Isso faz diferença de verdade quando uma variável recebe o valor dentro do loop:
fn main() { let mut n = 1; let answer; // ainda sem valor
loop { if n * n > 50 { answer = n * n; // definido logo antes de sair break; } n += 1; }
println!("O primeiro quadrado acima de 50 é {answer}");}Saída:
O primeiro quadrado acima de 50 é 64Com o loop, o Rust consegue ver que o único caminho até o println! passa por aquele break, então answer sempre tem valor. Troque loop por while true e você recebe error[E0381]: used binding answer is possibly-uninitialized, ou seja, a variável talvez não tenha sido inicializada. O compilador acha que o loop pode terminar sem executar o if nem uma vez.
Na prática, a versão mais limpa desse programa usa break com um valor, que você viu acima: let answer = loop { ... break n * n; ... };. De um jeito ou de outro, a lição é a mesma: quando você quer dizer “para sempre, até eu dar break”, escreva loop.
Quando usar o loop
Seção intitulada “Quando usar o loop”O loop é a escolha certa quando você não sabe de antemão quantas vezes vai repetir: você está esperando alguma condição se tornar verdadeira, e não contando um intervalo ou percorrendo uma lista. Para contar ou percorrer uma coleção, o while e o for (que vêm a seguir) costumam ficar mais legíveis.
Prática
Seção intitulada “Prática”1. Contagem regressiva para a decolagem
Seção intitulada “1. Contagem regressiva para a decolagem”Use loop para imprimir uma contagem regressiva de 5 até 1 e, depois, imprima Decolar!. Dica: comece com let mut n = 5; e dê break quando n chegar a 0.
Ver solução
fn main() { let mut n = 5;
loop { if n == 0 { break; } println!("{n}..."); n -= 1; }
println!("Decolar!");}Saída:
5...4...3...2...1...Decolar!A verificação vem primeiro, então quando n é 0 o loop para antes de imprimir 0....
2. A primeira potência de dois acima de 1000
Seção intitulada “2. A primeira potência de dois acima de 1000”Comece em 1 e vá dobrando. Use break com um valor para obter o primeiro número acima de 1000 e conte quantas vezes você dobrou. Dica: mantenha um contador mut fora do loop e escreva let power = loop { ... };.
Ver solução
fn main() { let mut value = 1; let mut doublings = 0;
let power = loop { value *= 2; doublings += 1; if value > 1000 { break value; } };
println!("{power} depois de dobrar {doublings} vezes");}Saída:
1024 depois de dobrar 10 vezesO break value; encerra o loop e entrega value para power. O contador fica fora do loop, então ele mantém o valor depois que o loop termina.
- O
looprepete para sempre até umbreakpará-lo; sempre garanta que exista um. break valor;para o loop e devolvevalorcomo resultado da expressão do loop inteiro.- Escreva
loop, e nãowhile true: o Rust sabe que o corpo de umloopsempre é executado, e isso o ajuda a verificar suas variáveis. - Use o
loopquando estiver repetindo “até alguma coisa acontecer”, e não quando estiver contando um número conhecido de vezes.
Teste o que aprendeu
Seção intitulada “Teste o que aprendeu”Teste o que aprendeu
1. O que impede um loop simples de rodar para sempre?
2. O que acontece ao escrever break count * 2; dentro de um loop?
3. Segundo esta página, quando o loop é melhor que o while ou o for?
4. O que acontece se você escrever while true { ... } em Rust?
Pontuação: 0 / 4
Para saber mais
Seção intitulada “Para saber mais”- Repetition with Loops — The Rust Book (em inglês): a introdução oficial ao
loop, aowhilee aofor. - Returning Values from Loops — The Rust Book (em inglês): uma seção curta sobre
breakcom um valor. - loop — Rust by Example (em inglês): exemplos executáveis de
loop,breakecontinue. - Returning from loops — Rust by Example (em inglês): mais um exemplo pequeno de um loop que devolve um valor.
- A palavra-chave
loop— documentação da std (em inglês): uma referência compacta de comoloopebreakfuncionam juntos.