Controle de Fluxo Let
Rust possui algumas construções de fluxo de controle que diferem de outras linguagens. Elas são usadas para correspondência de padrões:
- Expressões
if let - Expressões
let else - Expressões
while let
Expressões if let
A expressão if let lhe permite executar um código diferente caso um valor corresponde a um padrão:
use std::time::Duration;
fn sleep_for(secs: f32) {
if let Ok(dur) = Duration::try_from_secs_f32(secs) {
std::thread::sleep(dur);
println!("dormiu por {:?}", dur);
}
}
fn main() {
sleep_for(-10.0);
sleep_for(0.8);
}
Expressões let else
Para o caso comum de corresponder a um padrão e retornar da função, use let else. O caso “else” deve divergir (return, break ou pânico - qualquer coisa, exceto cair no final do bloco).
fn hex_or_die_trying(maybe_string: Option<String>) -> Result<u32, String> {
let s = if let Some(s) = maybe_string {
s
} else {
return Err(String::from("obteve None"));
};
let first_byte_char = if let Some(first_byte_char) = s.chars().next() {
first_byte_char
} else {
return Err(String::from("obteve uma string vazia"));
};
if let Some(digit) = first_byte_char.to_digit(16) {
Ok(digit)
} else {
Err(String::from("não é um dígito hexadecimal"))
}
}
fn main() {
println!("result: {:?}", hex_or_die_trying(Some(String::from("foo"))));
}
Similar a if let, há uma variante while let que testa repetidamente se um valor corresponde a um padrão:
fn main() {
let mut name = String::from("Comprehensive Rust 🦀");
while let Some(c) = name.pop() {
println!("character: {c}");
}
// (There are more efficient ways to reverse a string!)
}
Aqui String::pop retorna Some(c) até que a string esteja vazia e depois ela retornará None. O while let nos permite iterar por todos os itens.
if-let
- Ao contrário de
match,if letnão precisa cobrir todas as ramificações. Isso pode torná-lo mais conciso do quematch. - Um uso comum é lidar com valores
Someao trabalhar-se comOption. - Ao contrário de
match,if letnão suporta cláusulas de guarda para correspondência de padrões.
let-else
if-lets podem se acumular, como mostrado. A construção let-else permite o “achatamento” desse código aninhado. Reescreva a versão “estranha” para os alunos, para que eles possam ver a transformação.
A versão reescrita é:
#![allow(unused)]
fn main() {
fn hex_or_die_trying(maybe_string: Option<String>) -> Result<u32, String> {
let Some(s) = maybe_string else {
return Err(String::from("obteve None"));
};
let Some(first_byte_char) = s.chars().next() else {
return Err(String::from("obteve uma string vazia"));
};
let Some(digit) = first_byte_char.to_digit(16) else {
return Err(String::from("não é um dígito hexadecimal"));
};
return Ok(digit);
}
}
while-let
- Ressalte que o loop
while letcontinuará executando enquanto o valor corresponder ao padrão. - Você pode reescrever o loop
while letcomo um loop infinito com uma instruçãoifque é interrompido quando não houver mais nenhum valor para unwrap (desempacotar) paraname.pop(). Owhile letfornece um atalho para o cenário acima.