Rust by Example中文

16.7.2 Combining separate combinators

What if multiple Results needed to interact together? Is it still reasonably convenient? It turns out, not really.

use std::io::prelude::*; use std::fs::File; type Result<T> = std::result::Result<T, String>; // Setup to make this work. Create two files with some info. Ignore the // return values because we don't care about them here. fn setup() { File::create("a") .and_then(|mut file| file.write_all(b"grape")) .unwrap(); File::create("b") .and_then(|mut file| file.write_all(b"fruit")) .unwrap(); } // Get the data from each file with the data stored in a `Result`. fn get_data(path: &str) -> Result<String> { File::open(path) .map_err(|err| err.to_string()) .and_then(|mut file| { let mut contents = String::new(); // Read the data into `contents`. file.read_to_string(&mut contents) .map_err(|err| err.to_string()) // Ignore the output `read_to_string` returns and return `contents`. .map(|_| contents) }) } // Concat the contents of the two files together into a new `Result`. fn concat(filename_a: &str, filename_b: &str) -> Result<String> { let (data_a, data_b) = (get_data(filename_a), get_data(filename_b)); data_a.and_then(|a| // Return `Ok` when both `a` and `b` are `Ok`. Otherwise return // whichever has the first `Err`. data_b.and_then(|b| Ok(a + &b)) ) } fn main() { setup(); match concat("a", "b") { Ok(n) => println!("{}", n), Err(e) => println!("Error: {}", e), } }

What is happening is this approach tries to work with the data without ever removing the Ok wrapper on it. Sometimes it is a good approach but in this case it is really awkward. What if we could unwrap it without possibly inducing panic? That is where we are headed next.

See also:

Result and io::Result