Подтвердить что ты не робот

Как остановить итерацию и вернуть ошибку, когда Iterator:: map возвращает результат: Err?

У меня есть функция, которая возвращает Result:

fn find(id: &Id) -> Result<Item, ItemError> {
    // ...
}

Затем другой, используя его следующим образом:

let parent_items: Vec<Item> = parent_ids.iter()
    .map(|id| find(id).unwrap())
    .collect();

Как мне обрабатывать случай сбоя внутри любой из map итераций?

Я знаю, что могу использовать flat_map, и в этом случае ошибки будут проигнорированы:

let parent_items: Vec<Item> = parent_ids.iter()
    .flat_map(|id| find(id).into_iter())
    .collect();

Result Итератор имеет либо 0, либо 1 элемент в зависимости от состояния успеха, а flat_map будет отфильтровывать его, если он равен 0.

Однако я не хочу игнорировать ошибки, вместо этого хочу, чтобы весь блок кода просто остановился и возвратил новую ошибку (на основе ошибки, возникшей на карте или просто пересылающей существующую ошибку).

Как лучше всего справиться с этим в Rust?

4b9b3361

Ответ 1

Result реализует FromIterator, поэтому вы можете перемещать Result снаружи, и итераторы позаботятся об остальном (включая остановку итерации, если ошибка найдено).

#[derive(Debug)]
struct Item;
type Id = String;

fn find(id: &Id) -> Result<Item, String> {
    Err(format!("Not found: {:?}", id))
}

fn main() {
    let s = |s: &str| s.to_string();
    let ids = vec![s("1"), s("2"), s("3")];

    let items: Result<Vec<_>, _> = ids.iter().map(find).collect();
    println!("Result: {:?}", items);
}

Игровая площадка

Ответ 2

Этот ответ относится к версии ржавчины до версии 1.0, и необходимые функции были удалены

Вы можете использовать std::result::fold для этого. Он останавливает повторение после первого Err.

Пример программы, которую я только что написал:

fn main() {
  println!("{}", go([1, 2, 3]));
  println!("{}", go([1, -2, 3]));
}

fn go(v: &[int]) -> Result<Vec<int>, String> {
    std::result::fold(
        v.iter().map(|&n| is_positive(n)),
        vec![],
        |mut v, e| {
            v.push(e);
            v
        })
}

fn is_positive(n: int) -> Result<int, String> {
    if n > 0 {
        Ok(n)
    } else {
        Err(format!("{} is not positive!", n))
    }
}

Вывод:

Ok([1, 2, 3])
Err(-2 is not positive!)

Демо