Skip to the content.

Iterator で Result が出現する場合の対処

よく忘れて調べるか for loop で逃げてしまっているのでメモ
ResultOption に置き換えてもよし

Error を無視する

flat_map を使えば良い。

let source = vec!["3", ".", "1", "4"];
let v = source
    .iter()
    .flat_map(|x| x.parse::<u8>())
    .collect::<Vec<_>>();
assert_eq!(3, v[0]);
assert_eq!(1, v[1]);
assert_eq!(4, v[2]);

flat_mapシグネチャは以下の通り。
クロージャの戻り値の型が IntoIterator を実装していれば良い。

fn flat_map<U, F>(self, f: F) -> FlatMap<Self, U, F> ⓘ
where
    Self: Sized,
    U: IntoIterator,
    F: FnMut(Self::Item) -> U,

ResultIntoIterator実装しており、 Ok の場合は要素数 1 Err の場合は要素数 0 となる。

let x: Result<u32, &str> = Ok(5);
let v: Vec<u32> = x.into_iter().collect();
assert_eq!(v, [5]);

let x: Result<u32, &str> = Err("nothing!");
let v: Vec<u32> = x.into_iter().collect();
assert_eq!(v, []);

Result<Vec<_>, _> の型として扱う

colelct 時に Result<Vec<_>, _> を指定すれば良い。

let source = vec!["3", ".", "1", "4"];
let v = source
    .iter()
    .map(|x| x.parse::<u8>())
    .collect::<Result<Vec<_>, _>>();
assert!(v.is_err());

イテレータの中で最初に発生したエラーをエラーとして返す。
当然エラーが発生した時点で残りの要素は評価しない。

#[derive(PartialEq, Eq, Debug)]
enum Error {
    Zero,
    Minus,
}

struct X(i32);
impl X {
    // 1 以上の値でないとエラー
    fn value(&self) -> Result<i32, Error> {
        println!("X::value() = {}", self.0);
        if self.0 == 0 {
            Err(Error::Zero)
        } else if self.0 < 0 {
            Err(Error::Minus)
        } else {
            Ok(self.0)
        }
    }
}

let source = vec![X(0), X(-1), X(1)];
let v = source
    .iter()
    .map(|x| x.value())
    .collect::<Result<Vec<_>, _>>();
assert_eq!(Err(Error::Zero), v);

println!("--");
let source = vec![X(-1), X(0), X(1)];
let v = source
    .iter()
    .map(|x| x.value())
    .collect::<Result<Vec<_>, _>>();
assert_eq!(Err(Error::Minus), v);
$ cargo test -- --nocapture
...
running 1 test
X::value() = 0
--
X::value() = -1
...