I would like to write some code in a "functional programming" style.
However, I start with an Iterator of Results and I only want to apply the function to the Ok items. Furthermore, I want to stop the iteration on the first error (however, I'd be open to different behavior).
So far, I am using a nested map() pattern: <iter>.map(|l| l.map(replace)). I think this is extremely ugly.
Using the nightly "result_flattening", I can flatten each nested Result<Result<T, E>, E> into a Result<T, E>. Using eyre::Context I convert the different Error types into an eyre::Report error type. All of this feels quite clumsy.
What is an elegant way to write this in Rust?
Minimal Working Example
#![feature(result_flattening)] use std::io::BufRead; use eyre::Context; fn main() { let data = std::io::Cursor::new(b"FFBFFFBLLL\nBFBFBBFRLR\nFFFBFFBLLL"); let seats: Result<Vec<_>, _> = data .lines() .map(|l| l.map(replace).context("force eyre")) .map(|l| l.map(|s| u32::from_str_radix(&s, 2).context("force eyre"))) .map(|r| r.flatten()) .collect(); println!("{:#?}", seats); } fn replace(line: String) -> String { line.replace('F', "0") .replace('B', "1") .replace('L', "0") .replace('R', "1") } Further References:
- How do I stop iteration and return an error when Iterator::map returns a Result::Err?
- Result implements
FromIter. result_flatten: https://doc.rust-lang.org/std/result/enum.Result.html?search=#method.flatten, https://github.com/rust-lang/rust/issues/70142 (I'm using rustc 1.49.0-nightly (ffa2e7ae8 2020-10-24))lines()returnsResults: https://doc.rust-lang.org/std/io/trait.BufRead.html#method.lines