Pular para o conteúdo

For em Rust

O for percorre um intervalo ou uma coleção, um item de cada vez. Dos três tipos de laço do Rust, este é o que você vai usar mais.

fn main() {
for i in 1..=5 {
println!("{i}");
}
}

Saída:

1
2
3
4
5
▶ Experimente você mesmo

1..=5 é um intervalo (range) que inclui as duas pontas (de 1 a 5). Se você tirar o = e escrever 1..5, ele para um número antes, e você fica com 1 a 4. É fácil tropeçar nessa diferença de um, então vale conferir qual dos dois você quis usar.

É aqui que o for brilha de verdade: percorrer um array ou um vetor sem precisar controlar um índice por conta própria:

fn main() {
let fruits = ["maçã", "banana", "cereja"];
for fruit in fruits {
println!("{fruit}");
}
}

Saída:

maçã
banana
cereja
▶ Experimente você mesmo

Compare isso com contar na mão usando um while e acessar pelo índice (fruits[i]): fica mais curto e não existe índice para errar. Você vai aprender mais sobre arrays e vetores nas páginas de Arrays e Vetores.

Se você precisa da posição e do valor ao mesmo tempo, use .enumerate():

fn main() {
let fruits = ["maçã", "banana", "cereja"];
for (index, fruit) in fruits.iter().enumerate() {
println!("{index}: {fruit}");
}
}

Saída:

0: maçã
1: banana
2: cereja
▶ Experimente você mesmo

A parte (index, fruit) é um padrão de tupla: a cada volta você recebe um par, e o laço o separa em duas variáveis para você.

Contando de trás para frente e de tantos em tantos

Seção intitulada “Contando de trás para frente e de tantos em tantos”

E se você quiser contar de 3 para baixo, ou passar só por um número sim, outro não? Uma primeira tentativa natural é um intervalo ao contrário, como 3..=1. Ele compila, mas o laço nunca roda. Um intervalo só conta para cima, então um intervalo cujo início é maior que o fim está simplesmente vazio.

Em vez disso, use um intervalo normal e mude o jeito de percorrê-lo:

  • .rev() percorre o intervalo ao contrário.
  • .step_by(n) pega um valor a cada n, começando pelo primeiro.
fn main() {
for i in (1..=3).rev() {
println!("{i}...");
}
println!("Já!");
for even in (0..=10).step_by(2) {
print!("{even} ");
}
println!();
for i in 3..=1 {
println!("isto nunca aparece: {i}");
}
}

Saída:

3...
2...
1...
Já!
0 2 4 6 8 10
▶ Experimente você mesmo

Repare nos parênteses: (1..=3).rev(). Sem eles, o Rust leria 1..=3.rev() como “de 1 até 3.rev()”, que não é o que você quer. Você também pode combinar os dois: (0..=10).rev().step_by(5) dá 10, 5, 0.

Você poderia escrever um laço de contagem com while, mas o for com um intervalo elimina toda uma categoria de erros: não existe contador manual para esquecer de atualizar nem risco de passar uma posição além do fim de um array. Quem programa em Rust usa o for por padrão e só recorre ao while quando não há um intervalo ou uma coleção natural para percorrer.

Imprima a tabuada do 7, de 7 x 1 = 7 até 7 x 10 = 70. Dica: um único laço for sobre 1..=10 basta. Você pode fazer a multiplicação direto dentro do println!.

Ver solução
fn main() {
for i in 1..=10 {
println!("7 x {i} = {}", 7 * i);
}
}

Saída:

7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
7 x 6 = 42
7 x 7 = 49
7 x 8 = 56
7 x 9 = 63
7 x 10 = 70
▶ Experimente você mesmo

Variáveis com nome, como {i}, podem ir direto dentro das chaves. Um cálculo como 7 * i não pode, então ele usa um {} vazio com o valor depois da vírgula.

Some todos os números ímpares de 1 a 99 e imprima o total. Dica: (1..100).step_by(2) dá 1, 3, 5, … 99. Mantenha um total mut fora do laço.

Ver solução
fn main() {
let mut total = 0;
for n in (1..100).step_by(2) {
total += n;
}
println!("A soma dos ímpares de 1 a 99 é {total}");
}

Saída:

A soma dos ímpares de 1 a 99 é 2500
▶ Experimente você mesmo

Outro jeito é percorrer 1..100 e só somar n quando n % 2 == 1. Os dois funcionam. O step_by só pula os números pares em vez de verificar cada um.

  • for item in intervalo_ou_coleção { ... } é o laço do dia a dia em Rust.
  • 1..=5 inclui as duas pontas; 1..5 para um número antes do 5.
  • Percorra arrays e vetores diretamente para pegar cada valor sem acessar índices na mão.
  • Use .enumerate() quando precisar do índice junto com o valor.
  • Um intervalo ao contrário, como 3..=1, está vazio. Use (1..=3).rev() para contar para baixo e .step_by(n) para pular valores.

Teste o que aprendeu

1. Qual é a diferença entre 1..=5 e 1..5 em um laço for?

2. Como obter o índice e o valor ao mesmo tempo ao percorrer uma coleção?

3. Por que o for costuma ser preferido ao while para percorrer uma coleção?

4. O que for i in 5..=1 { ... } faz?

Pontuação: 0 / 4