Pular para o conteúdo

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.

fn main() {
let mut count = 0;
loop {
count += 1;
println!("{count}");
if count == 3 {
break;
}
}
}

Saída:

1
2
3
▶ Experimente você mesmo

Sozinho, o loop nunca para: quem o encerra é o break. Sem aquele if count == 3 { break; }, este programa ficaria imprimindo para sempre.

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:

20
▶ Experimente você mesmo

Isso é ú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;.

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 é 64
▶ Experimente você mesmo

Com 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.

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.

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!
▶ Experimente você mesmo

A verificação vem primeiro, então quando n é 0 o loop para antes de imprimir 0....

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 vezes
▶ Experimente você mesmo

O 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 loop repete para sempre até um break pará-lo; sempre garanta que exista um.
  • break valor; para o loop e devolve valor como resultado da expressão do loop inteiro.
  • Escreva loop, e não while true: o Rust sabe que o corpo de um loop sempre é executado, e isso o ajuda a verificar suas variáveis.
  • Use o loop quando estiver repetindo “até alguma coisa acontecer”, e não quando estiver contando um número conhecido de vezes.

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