Controle de fluxo
Esta aula ensina controle de fluxo em Rust, destacando que if/else são expressões que retornam valores, os diferentes tipos de loops (loop, while, for), a capacidade de retornar valores com break, e o uso de labels para aninhar e controlar loops. O conteúdo inclui exemplos práticos e exercícios para fixação.
O controle de fluxo é fundamental em qualquer linguagem de programação. Em Rust, as estruturas de controle são poderosas e seguras, garantindo que todas as ramificações sejam consideradas. Nesta aula, exploraremos como usar if, else, loops e técnicas avançadas como break com valor e labels de loop.
Diferentemente de muitas linguagens, em Rust if é uma expressão, não uma declaração. Isso significa que ela pode retornar um valor, permitindo código mais conciso e funcional. Além disso, os loops podem ser aninhados e controlados com labels, e o for é uma ferramenta elegante para iterar sobre coleções.
if/else como expressão
Em Rust, if e else são expressões que produzem um valor. Isso permite atribuir o resultado de uma condicional diretamente a uma variável. A sintaxe é similar a outras linguagens, mas a última expressão em cada bloco é o valor retornado.
Por exemplo:
let numero = 7;
let resultado = if numero % 2 == 0 {
"par"
} else {
"ímpar"
};
println!("O número {} é {}.", numero, resultado);Note que ambos os blocos devem retornar valores do mesmo tipo. Caso contrário, o compilador emitirá um erro. Isso garante segurança de tipo.
É possível encadear múltiplas condições com else if:
let nota = 85;
let conceito = if nota >= 90 {
"A"
} else if nota >= 80 {
"B"
} else if nota >= 70 {
"C"
} else {
"D"
};
println!("Conceito: {}", conceito);Use if como expressão sempre que possível para tornar o código mais limpo e evitar mutabilidade desnecessária.
loop, while e for
Rust oferece três tipos de loops: loop, while e for. O loop é o mais simples: ele repete um bloco de código indefinidamente até que um break seja encontrado. É útil quando a condição de parada não é simples ou quando precisamos de um loop infinito controlado.
let mut contador = 0;
loop {
println!("Contagem: {}", contador);
contador += 1;
if contador == 5 {
break;
}
}O while executa enquanto uma condição booleana for verdadeira. É ideal quando a condição é verificada antes de cada iteração.
let mut numero = 3;
while numero > 0 {
println!("{}!", numero);
numero -= 1;
}
println!("Lançar!");O for é usado para iterar sobre elementos de uma coleção, como arrays, intervalos ou iteradores. É a forma mais segura e idiomática de percorrer coleções.
let array = [10, 20, 30, 40];
for elemento in array.iter() {
println!("Valor: {}", elemento);
}
// Usando um intervalo (range)
for numero in 1..5 {
println!("Número: {}", numero);
}O for com intervalos é exclusivo e não inclui o limite superior (1..5 produz 1,2,3,4). Use 1..=5 para incluir 5.
break com valor
Uma característica poderosa de Rust é que o break pode retornar um valor do loop. Isso é especialmente útil para loops que precisam produzir um resultado. O valor após a palavra-chave break é retornado como o valor da expressão loop.
let mut contador = 0;
let resultado = loop {
contador += 1;
if contador == 10 {
break contador * 2; // retorna 20
}
};
println!("Resultado: {}", resultado);Isso funciona apenas com loop, pois while e for são expressões que retornam () (unidade). O break com valor permite escrever algoritmos que, de outra forma, exigiriam variáveis mutáveis externas.
Exemplo prático: encontrar o primeiro número inteiro que satisfaz uma condição.
let numero = loop {
let n = rand::random::<i32>(); // supondo crate rand
if n > 0 && n % 7 == 0 {
break n;
}
};
println!("Número encontrado: {}", numero);Labels de loop
Quando loops são aninhados, labels permitem especificar qual loop o break ou continue deve afetar. Uma label é um identificador seguido de dois pontos, colocado antes do loop.
'externo: for i in 1..=3 {
'interno: for j in 1..=3 {
if i == 2 && j == 2 {
break 'externo; // sai do loop externo
}
println!("i: {}, j: {}", i, j);
}
}Sem a label, o break sairia apenas do loop interno. Com a label, podemos sair de qualquer nível. Da mesma forma, continue pode ser usado com labels para pular iterações em loops externos.
Labels são úteis em situações como busca em matrizes, onde ao encontrar um elemento, desejamos interromper a busca completamente.
let matriz = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
let mut encontrado = false;
'busca: for linha in &matriz {
for &valor in linha {
if valor == 5 {
encontrado = true;
break 'busca;
}
}
}
println!("Encontrado: {}", encontrado);Referências
- The Rust Programming Language - Control Flow
- Rust by Example - Flow Control
- Rust Reference - If expressions
- Rust Reference - Loop expressions
- Rust std - break keyword
Exercícios
- Escreva um programa que use
ifcomo expressão para atribuir a uma variável a string "maior" se um número for maior que 10, ou "menor ou igual" caso contrário. Imprima o resultado. - Use um loop
whilepara imprimir os números de 1 a 5, cada um em uma linha. - Crie um loop
forque itere sobre um array de nomes e imprima cada nome em maiúsculas. - Escreva uma função que receba um número e use um loop
loopcombreakretornando o fatorial desse número. - Use labels de loop para encontrar o primeiro par (i, j) com i de 1 a 3 e j de 1 a 3 tal que i * j > 4. Imprima o par e pare todos os loops.
fn main() {
let numero = 15;
let resultado = if numero > 10 { "maior" } else { "menor ou igual" };
println!("O número é {} que 10.", resultado);
}fn main() {
let mut i = 1;
while i <= 5 {
println!("{}", i);
i += 1;
}
}fn main() {
let nomes = ["ana", "joão", "maria"];
for nome in nomes.iter() {
println!("{}", nome.to_uppercase());
}
}fn fatorial(n: u32) -> u32 {
let mut acc = 1;
let mut i = 1;
loop {
if i > n {
break acc;
}
acc *= i;
i += 1;
}
}
fn main() {
println!("Fatorial de 5: {}", fatorial(5));
}fn main() {
'externo: for i in 1..=3 {
for j in 1..=3 {
if i * j > 4 {
println!("Par: ({}, {})", i, j);
break 'externo;
}
}
}
}