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()
returnsResult
s: https://doc.rust-lang.org/std/io/trait.BufRead.html#method.lines