if let e while let
Esta aula cobre as construções if let e while let em Rust, que são açúcares sintáticos para match em casos específicos. Aprenda quando e como usá-las para escrever código mais conciso e legível, combinando-as com else e vendo exemplos práticos.
Em Rust, o match é uma ferramenta poderosa para controle de fluxo baseado em padrões. No entanto, em situações onde você só se importa com um único padrão, o match pode parecer verboso. Para esses casos, Rust oferece construções mais concisas: if let e while let. Elas são açúcares sintáticos que simplificam o código, mantendo a segurança e expressividade do sistema de padrões.
Açúcar para match
if let é uma forma compacta de usar match quando você quer executar código apenas se um valor corresponder a um determinado padrão, ignorando os outros casos. Por exemplo, ao invés de escrever:
let optional = Some(5);
match optional {
Some(x) => println!("O valor é {}", x),
_ => (),
}
Você pode usar if let:
if let Some(x) = optional {
println!("O valor é {}", x);
}
Da mesma forma, while let repete um loop enquanto um padrão corresponde a um valor. É útil para iterar sobre iteradores que retornam Option ou Result. Exemplo:
let mut stack = Vec::new();
stack.push(1);
stack.push(2);
stack.push(3);
while let Some(top) = stack.pop() {
println!("{}", top);
}
Isso substitui um match dentro de um loop loop com verificação de padrão e break.
Quando usar
Use if let quando você só se importa com um caso de um enum ou um valor que implementa Into para um padrão. É ideal para desestruturar Option, Result ou enums personalizados onde apenas uma variante é relevante. Evite usar if let quando você precisa lidar com múltiplos casos — nesse caso, match é mais adequado.
while let é útil para loops que devem continuar enquanto uma condição de padrão for verdadeira. É comum em iteradores que retornam Option (como next()) ou em situações onde você está consumindo uma estrutura de dados até que ela se esgote. Por exemplo, ao ler linhas de um arquivo com BufReader, que retorna Option<Result<String>>, você pode usar while let para processar cada linha.
Combinando com else
if let pode ser combinado com else para executar código quando o padrão não corresponde. Isso é equivalente a um match com um braço _. Exemplo:
let number = Some(7);
if let Some(x) = number {
println!("Número: {}", x);
} else {
println!("Nenhum número");
}
Você também pode encadear if let com else if let para verificar múltiplos padrões, embora isso possa se tornar menos legível que um match.
Para while let, não há uma cláusula else direta, mas você pode usar um if dentro do loop para verificar se o padrão falhou, ou usar break.
Exemplos
Exemplo 1: Option com if let
fn main() {
let x: Option = Some(10);
if let Some(val) = x {
println!("Valor: {}", val);
} else {
println!("Nenhum valor");
}
}
Exemplo 2: Result com if let
fn main() {
let result: Result = Ok(42);
if let Ok(num) = result {
println!("Sucesso: {}", num);
} else {
println!("Erro");
}
}
Exemplo 3: Enum personalizado
enum Mensagem {
Texto(String),
Sair,
}
fn main() {
let msg = Mensagem::Texto(String::from("Olá"));
if let Mensagem::Texto(t) = msg {
println!("Mensagem: {}", t);
}
}
Exemplo 4: while let com iterador
fn main() {
let valores = vec![1, 2, 3, 4, 5];
let mut iter = valores.iter();
while let Some(num) = iter.next() {
println!("Número: {}", num);
}
}
Exemplo 5: while let com Option retornado por função
fn proximo_par(limite: i32) -> Option {
if limite < 0 { None } else { Some(limite + 2) }
}
fn main() {
let mut atual = 0;
while let Some(par) = proximo_par(atual) {
println!("Par: {}", par);
atual = par;
if atual > 10 { break; }
}
}
Boas práticas
- Prefira
if letquando você só precisa de um caso, pois é mais conciso e claro. - Evite encadear muitos
else if let; nesse caso,matché mais legível. - Use
while letpara loops que consomem iteradores ou padrões que mudam. - Lembre-se de que
if letewhile letfuncionam com qualquer padrão, não apenas com enums.
Referências
- The Rust Programming Language - if let
- Rust by Example - if let
- Rust Reference - if let expressions
- Rust std::keyword::while
- Patterns and Matching
Exercícios
-
Escreva uma função que recebe um
Option<i32>e imprime o valor se forSome, caso contrário imprime "Nada". Useif let.✓ Resposta:fn imprimir_opcional(x: Option) { if let Some(val) = x { println!("{}", val); } else { println!("Nada"); } } -
Use
while letpara consumir um iterador de números até que ele retorneNone, imprimindo cada número.✓ Resposta:fn main() { let numeros = vec![1, 2, 3]; let mut iter = numeros.iter(); while let Some(num) = iter.next() { println!("{}", num); } } -
Crie um enum
Corcom variantesRGB(u8, u8, u8)eHex(String). Useif letpara extrair o valor RGB e imprimir.✓ Resposta:enum Cor { RGB(u8, u8, u8), Hex(String), } fn main() { let cor = Cor::RGB(255, 0, 0); if let Cor::RGB(r, g, b) = cor { println!("RGB: ({}, {}, {})", r, g, b); } } -
Escreva um loop que use
while letpara ler linhas de uma string (simulando um buffer) até encontrar uma linha vazia. Uselines().✓ Resposta:fn main() { let texto = "linha1\nlinha2\n\nlinha3"; let mut linhas = texto.lines(); while let Some(linha) = linhas.next() { if linha.is_empty() { break; } println!("{}", linha); } } -
Dado um
Result<i32, String>, useif letcomelsepara imprimir o valor se forOkou a mensagem de erro se forErr.✓ Resposta:fn main() { let resultado: Result= Ok(10); if let Ok(val) = resultado { println!("Valor: {}", val); } else if let Err(err) = resultado { println!("Erro: {}", err); } }