Iterando sobre Resultados

Beginner

This tutorial is from open-source community. Access the source code

Introdução

Neste laboratório, exploramos diferentes estratégias para lidar com a possibilidade de falhas ao iterar sobre uma coleção de Results em Rust.

Nota: Se o laboratório não especificar um nome de arquivo, você pode usar qualquer nome de arquivo que desejar. Por exemplo, você pode usar main.rs, compilar e executá-lo com rustc main.rs && ./main.

Iterando sobre Results

Uma operação Iter::map pode falhar, por exemplo:

fn main() {
    let strings = vec!["tofu", "93", "18"];
    let numbers: Vec<_> = strings
        .into_iter()
        .map(|s| s.parse::<i32>())
        .collect();
    println!("Results: {:?}", numbers);
}

Vamos analisar as estratégias para lidar com isso.

Ignorar os itens com falha com filter_map()

filter_map chama uma função e filtra os resultados que são None.

fn main() {
    let strings = vec!["tofu", "93", "18"];
    let numbers: Vec<_> = strings
        .into_iter()
        .filter_map(|s| s.parse::<i32>().ok())
        .collect();
    println!("Results: {:?}", numbers);
}

Coletar os itens com falha com map_err() e filter_map()

map_err chama uma função com o erro, então, adicionando isso à solução filter_map anterior, podemos salvá-los de lado durante a iteração.

fn main() {
    let strings = vec!["42", "tofu", "93", "999", "18"];
    let mut errors = vec![];
    let numbers: Vec<_> = strings
        .into_iter()
        .map(|s| s.parse::<u8>())
        .filter_map(|r| r.map_err(|e| errors.push(e)).ok())
        .collect();
    println!("Numbers: {:?}", numbers);
    println!("Errors: {:?}", errors);
}

Falhar em toda a operação com collect()

Result implementa FromIterator para que um vetor de resultados (Vec<Result<T, E>>) possa ser transformado em um resultado com um vetor (Result<Vec<T>, E>). Assim que um Result::Err é encontrado, a iteração será encerrada.

fn main() {
    let strings = vec!["tofu", "93", "18"];
    let numbers: Result<Vec<_>, _> = strings
        .into_iter()
        .map(|s| s.parse::<i32>())
        .collect();
    println!("Results: {:?}", numbers);
}

Esta mesma técnica pode ser usada com Option.

Coletar todos os valores válidos e falhas com partition()

fn main() {
    let strings = vec!["tofu", "93", "18"];
    let (numbers, errors): (Vec<_>, Vec<_>) = strings
        .into_iter()
        .map(|s| s.parse::<i32>())
        .partition(Result::is_ok);
    println!("Numbers: {:?}", numbers);
    println!("Errors: {:?}", errors);
}

Ao olhar para os resultados, você notará que tudo ainda está envolvido em Result. Um pouco mais de código boilerplate é necessário para isso.

fn main() {
    let strings = vec!["tofu", "93", "18"];
    let (numbers, errors): (Vec<_>, Vec<_>) = strings
        .into_iter()
        .map(|s| s.parse::<i32>())
        .partition(Result::is_ok);
    let numbers: Vec<_> = numbers.into_iter().map(Result::unwrap).collect();
    let errors: Vec<_> = errors.into_iter().map(Result::unwrap_err).collect();
    println!("Numbers: {:?}", numbers);
    println!("Errors: {:?}", errors);
}

Resumo

Parabéns! Você concluiu o laboratório Iterating Over Results. Você pode praticar mais laboratórios no LabEx para aprimorar suas habilidades.