Update: The message header has been updated and the answer has been removed from the question. Short answer: you cannot. Please see my answer to this question.
I am following the blog post about the error here (github for here ), and I tried to make some changes to the code, so the search function returns an Iterator instead of Vec . It was insanely complicated and I was stuck.
I got to this point:
fn search<'a, P: AsRef<Path>>(file_path: &Option<P>, city: &str) -> Result<FilterMap<csv::reader::DecodedRecords<'a, Box<Read>, Row>, FnMut(Result<Row, csv::Error>) -> Option<Result<PopulationCount, csv::Error>>>, CliError> { let mut found = vec![]; let input: Box<io::Read> = match *file_path { None => Box::new(io::stdin()), Some(ref file_path) => Box::new(try!(fs::File::open(file_path))), }; let mut rdr = csv::Reader::from_reader(input); let closure = |row: Result<Row, csv::Error>| -> Option<Result<PopulationCount, csv::Error>> { let row = match row { Ok(row) => row, Err(err) => return Some(Err(From::from(err))), }; match row.population { None => None, Some(count) => if row.city == city { Some(Ok(PopulationCount { city: row.city, country: row.country, count: count, })) } else { None } } }; let found = rdr.decode::<Row>().filter_map(closure); if !found.all(|row| match row { Ok(_) => true, _ => false, }) { Err(CliError::NotFound) } else { Ok(found) } }
with the following compiler error:
src/main.rs:97:1: 133:2 error: the trait `core::marker::Sized` is not implemented for the type `core::ops::FnMut(core::result::Result<Row, csv::Error>) -> core::option::Option<core::result::Result<PopulationCount, csv::Error>>` [E0277] src/main.rs:97 fn search<'a, P: AsRef<Path>>(file_path: &Option<P>, city: &str) -> Result<FilterMap<csv::reader::DecodedRecords<'a, Box<Read>, Row>, FnMut(Result<Row, csv::Error>) -> Option<Result<PopulationCount, csv::Error>>>, CliError> { src/main.rs:98 let mut found = vec![]; src/main.rs:99 let input: Box<io::Read> = match *file_path { src/main.rs:100 None => Box::new(io::stdin()), src/main.rs:101 Some(ref file_path) => Box::new(try!(fs::File::open(file_path))), src/main.rs:102 }; ... src/main.rs:97:1: 133:2 note: `core::ops::FnMut(core::result::Result<Row, csv::Error>) -> core::option::Option<core::result::Result<PopulationCount, csv::Error>>` does not have a constant size known at compile-time src/main.rs:97 fn search<'a, P: AsRef<Path>>(file_path: &Option<P>, city: &str) -> Result<FilterMap<csv::reader::DecodedRecords<'a, Box<Read>, Row>, FnMut(Result<Row, csv::Error>) -> Option<Result<PopulationCount, csv::Error>>>, CliError> { src/main.rs:98 let mut found = vec![]; src/main.rs:99 let input: Box<io::Read> = match *file_path { src/main.rs:100 None => Box::new(io::stdin()), src/main.rs:101 Some(ref file_path) => Box::new(try!(fs::File::open(file_path))), src/main.rs:102 }; ... error: aborting due to previous error
I also tried defining this function:
fn search<'a, P: AsRef<Path>, F>(file_path: &Option<P>, city: &str) -> Result<FilterMap<csv::reader::DecodedRecords<'a, Box<Read>, Row>, F>, CliError> where F: FnMut(Result<Row, csv::Error>) -> Option<Result<PopulationCount, csv::Error>> {
with these compiler errors:
src/main.rs:131:12: 131:17 error: mismatched types: expected `core::iter::FilterMap<csv::reader::DecodedRecords<'_, Box<std::io::Read>, Row>, F>`, found `core::iter::FilterMap<csv::reader::DecodedRecords<'_, Box<std::io::Read>, Row>, [closure src/main.rs:105:19: 122:6]>` (expected type parameter, found closure) [E0308] src/main.rs:131 Ok(found)
I cannot close Box , because then filter_map will not be accepted.
Then I tried this:
fn search<'a, P: AsRef<Path>>(file_path: &Option<P>, city: &'a str) -> Result<(Box<Iterator<Item=Result<PopulationCount, csv::Error>> + 'a>, csv::Reader<Box<io::Read>>), CliError> { let input: Box<io::Read> = match *file_path { None => box io::stdin(), Some(ref file_path) => box try!(fs::File::open(file_path)), }; let mut rdr = csv::Reader::from_reader(input); let mut found = rdr.decode::<Row>().filter_map(move |row| { let row = match row { Ok(row) => row, Err(err) => return Some(Err(err)), }; match row.population { None => None, Some(count) if row.city == city => { Some(Ok(PopulationCount { city: row.city, country: row.country, count: count, })) }, _ => None, } }); if found.size_hint().0 == 0 { Err(CliError::NotFound) } else { Ok((box found, rdr)) } } fn main() { let args: Args = Docopt::new(USAGE) .and_then(|d| d.decode()) .unwrap_or_else(|err| err.exit()); match search(&args.arg_data_path, &args.arg_city) { Err(CliError::NotFound) if args.flag_quiet => process::exit(1), Err(err) => fatal!("{}", err), Ok((pops, rdr)) => for pop in pops { match pop { Err(err) => panic!(err), Ok(pop) => println!("{}, {}: {} - {:?}", pop.city, pop.country, pop.count, rdr.byte_offset()), } } } }
Which gives me this error:
src/main.rs:107:21: 107:24 error: `rdr` does not live long enough src/main.rs:107 let mut found = rdr.decode::<Row>().filter_map(move |row| { ^~~ src/main.rs:100:117: 130:2 note: reference must be valid for the lifetime 'a as defined on the block at 100:116... src/main.rs:100 -> Result<(Box<Iterator<Item=Result<PopulationCount, csv::Error>> + 'a>, csv::Reader<Box<io::Read>>), CliError> { src/main.rs:101 let input: Box<io::Read> = match *file_path { src/main.rs:102 None => box io::stdin(), src/main.rs:103 Some(ref file_path) => box try!(fs::File::open(file_path)), src/main.rs:104 }; src/main.rs:105 ... src/main.rs:106:51: 130:2 note: ...but borrowed value is only valid for the block suffix following statement 1 at 106:50 src/main.rs:106 let mut rdr = csv::Reader::from_reader(input); src/main.rs:107 let mut found = rdr.decode::<Row>().filter_map(move |row| { src/main.rs:108 let row = match row { src/main.rs:109 Ok(row) => row, src/main.rs:110 Err(err) => return Some(Err(err)), src/main.rs:111 }; ... error: aborting due to previous error
Am I doing something wrong, or am I mistaken? Did I miss something really simple and stupid? I'm not sure where to go from here.