Предположим, у меня есть коллекция элементов Результат, например:
let items: &[Result<&str, u32>] = &[Ok("foo"), Err(444), Ok("bar")];
Мне нужно найти индекс первого элемента со значением "bar"
. Моя первая попытка выглядит так:
let bar_idx = items.iter()
.position(|item| item? == "bar")?;
Это не сработает из-за оператора ?
внутри замыкания.
Мне известен метод try_for_each , который завершает работу всей коллекции неудачно, если возвращается Err
, но такого эквивалента для позиции не существует, что я и пытаюсь сделать.
Как реализовать этот поиск?
Обновлено:
Я открыл вопрос в репозитории Rust, потому что считаю, что try_position
должен существовать.
Вы можете построить его поверх try_for_each()
:
use std::ops::ControlFlow;
let item: ControlFlow<Result<usize, u32>> =
items
.iter()
.enumerate()
.try_for_each(|(idx, item)| match item {
Ok(v) if *v == "bar" => ControlFlow::Break(Ok(idx)),
Ok(_) => ControlFlow::Continue(()),
Err(err) => ControlFlow::Break(Err(*err)),
});
// Can replace by `ControlFlow::break_value()` once stabilized.
let item = match item {
ControlFlow::Break(v) => Some(v),
ControlFlow::Continue(()) => None,
};
Но, честно говоря, лучше использовать простой цикл for
:
let mut result = None;
for (idx, item) in items.iter().enumerate() {
match item {
Ok(v) if *v == "bar" => {
result = Some(Ok(idx));
break;
}
Ok(_) => {}
Err(err) => {
result = Some(Err(*err));
break;
}
}
}
fn main() {
let items: &[Result<&str, u32>] = &[Ok("foo"), Err(404), Ok("bar")];
// find the index of the first element with the value "bar"
let idx1 = items.iter().position(|x| x.is_ok_and(|x| x == "bar"));
println!("{:?}", idx1);
// or you can combine `enumerate`,`find` and `map` to find the index
let idx2 = items.iter()
.enumerate()
.find(|(index, value)| {
if **value == Ok("bar") {
true
} else {
false
}
})
.map(|x| x.0);
println!("{:?}", idx2);
}
Оба выведите Some(2)
сюда. Если ничего не найдено, выведите None
.
if <expr> { true } else { false }
то же самое, что и просто <expr>
.
Ни одно из этих предложений не приводит к ошибке при обнаружении ошибки на раннем этапе, поэтому я думаю, что это не соответствует сути вопроса.
Версия с циклом for станет еще проще, если вы обернете ее функцией, возвращающей
Result
, и используете?
для раннего выхода при ошибке: play.rust-lang.org/…