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 while let
  • ExpressĂ”es match (correspondĂȘncia)

ExpressÔes if let

A expressĂŁo if let lhe permite executar um cĂłdigo diferente caso um valor corresponde a um padrĂŁo:

fn sleep_for(secs: f32) {
    let dur = if let Ok(dur) = std::time::Duration::try_from_secs_f32(secs) {
        dur
    } else {
        std::time::Duration::from_millis(500)
    };
    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.

This slide should take about 10 minutes.

if-let

  • Ao contrĂĄrio de match, if let nĂŁo precisa cobrir todas as ramificaçÔes. Isso pode tornĂĄ-lo mais conciso do que match.
  • Um uso comum Ă© lidar com valores Some ao trabalhar-se com Option.
  • Ao contrĂĄrio de match, if let nĂŁ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 let continuarĂĄ executando enquanto o valor corresponder ao padrĂŁo.
  • VocĂȘ pode reescrever o loop while let como um loop infinito com uma instrução if que Ă© interrompido quando nĂŁo houver mais nenhum valor para unwrap (desempacotar) para name.pop(). O while let fornece um atalho para o cenĂĄrio acima.