I'm trying to change the minigrep application that I've implemented in the rust book to also take stdin input like the real grep does.
I've created a small helper function that takes the configuration and decides (currently according to an environment variable) whether to return the buffered reader iterator or the stdin iterator:
fn stdinOrFile(cfg: &Cfg) -> impl Iterator<Item = String> + '_ {
if cfg.stdin {
return io::stdin().lines();
}
let file = File::open(cfg.path.clone()).unwrap();
let reader = BufReader::new(file);
return reader.lines();
}
Realizing that I'm poking with a stick in the dark, it appears that the syntax of returning a trait object is legal, it's a dead-end for now thought. The compiler appears to still try to infer the concrete type of the returned value and complains that the other type is not of the same type, however to the best of my knowledge both implement the iterator trait.
Some ideas I have to get around this:
Box the value before returning itminigrep matcher only uses the filter functionality of the iterators, I could have separate filter implementations on the wrapper according to which underlying type it holds, which would then call the relevant method on the underlying type.Any ideas? Why is the trait object syntax allowed in the return type if a concrete implementation is inferred?
You're right to think you should box it. impl Iterator is not a trait object. It can mean a couple of different things, but in return position it's a special impl return syntax. Effectively, the function still returns a concrete, ordinary iterator of known type, it's just that the compiler infers that type for you. It's most commonly used with iterators, since writing impl Iterator<Item=u32> is far nicer than the actual return type which can be some shenanigans like Map<Vec::Iter<String>, fn(String) -> i32> (and can even be non-denotable in cases where the function argument is a closure).
However, with impl return, there must still exist a concrete type. You can't return two different types in two different branches. So in this case, you do need a trait object. That's dyn Iterator, but dyn Iterator is not sized, so you need to wrap it in a Box to deal with that.
Box<dyn Iterator<Item = String> + '_>
and, of course, you'll need to wrap your return values in Box::new, since Rust won't do that for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With