How to handle stream map closure return type


#1

This is perhaps not the best way to do this however for sanity sake and to better understand the language what would the return type be for the function below: I can’t seem to figure it out.

fn unpack_file(parser: &SomeProcessor, path: std::path::PathBuf) -> ??? {
    let file = OpenOptions::new()
            .read(true)
            .open(path.as_path()).unwrap();
    let reader = io::BufReader::new(file);
    let path_str = path.to_str().unwrap().to_string();
    let stream = reader.lines().enumerate().map(|(i,line)| {
        line.map_err(|e| LineError(SomeError::IoError(e), i,path_str.to_owned()))
          .and_then(|record: String| {
              parser.process(&record).map_err(|e| LineError(e, i,path_str.to_owned()))
          })
    });
    stream
}

Compiler says:

187 |     stream
    |     ^^^^^^ expected struct `???`, found struct `std::iter::Map`
    |
    = note: expected type `???'
               found type `std::iter::Map<std::iter::Enumerate<std::io::Lines<std::io::BufReader<std::fs::File>>>, [closure@src/main.rs:181:49: 186:6 path_str:_, parser:_]>`

#2

found type std::iter::Map<std::iter::Enumerate<std::io::Lines<std::io::BufReader<std::fs::File>>>, [closure@src/main.rs:181:49: 186:6 path_str:_, parser:_]>

Yeah, that’s its type - you can’t write it down because you can’t write down the type of a closure. But one possible signature for the function would be (using the impl Trait syntax):

fn unpack_file(parser: &SomeProcessor, path: std::path::PathBuf) -> impl Iterator<Item = ???>

where ??? is the result of parser.process(&record), but with LineError as the error type.


#3

So how do I return stream so I can use it in the caller?


#4

Edited!


#5
pub trait LineProcessor<T> {
    fn process(&self, line: &str) -> LineResult<T>;
}

so then I:

fn unpack_file(parser: &SomeProcessor, path: std::path::PathBuf) -> impl Iterator<Result<LineResult, LineError>> {
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected no type arguments


#6

Sorry, I’m stupid! It’s actually:

fn unpack_file(parser: &SomeProcessor, path: std::path::PathBuf) -> impl Iterator<Item = ???>;

#7

I guess that makes sense. Compiler still confused:

error: `impl Trait` in return position is experimental (see issue #34511)
   --> src/main.rs:174:76
    |
174 | fn unpack_file(parser: &SomeProcessor, path: std::path::PathBuf) -> impl Iterator<Item = LineResult> {
    |                                                                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error[E0243]: wrong number of type arguments: expected 1, found 0
   --> src/main.rs:174:97
    |
174 | fn unpack_file(parser: &SomeProcessor, path: std::path::PathBuf) -> impl Iterator<Item = LineResult> {
    |                                                                                                 ^^^^^^^^^^ expected 1 type argument

error: aborting due to 2 previous errors


#8

Is it because

LineResult<T>?

#9

Probably? Also, you need to be on nightly and add #![feature(conservative_impl_trait)] to the top of your main.rs or lib.rs for impl Trait to work right now.


#10
error[E0554]: #![feature] may not be used on the stable release channel
 --> src/main.rs:1:1
  |
1 | #![feature(conservative_impl_trait)]

not sure what this mean :stuck_out_tongue:


#11

You need to use the nightly channel to use impl Trait right now, because the details and implementation are still being worked out. See the book for more information:

https://doc.rust-lang.org/book/first-edition/release-channels.html


#12

Ok cool I will test that, thanks for the help. Just curious is there a way to do it with a non impl also?


#13

You can return a Box<Iterator<Item=...>>.


#14

^^^ Thanks!