Hi, the below works as expected, that is, I can pass as an arg to that fn any csv reader, be it created from file, stdin etc.
fn bar<R: std::io::Read>(rdr:&mut csv::Reader<R>) {}//works
The below on the other hand doesn't:
fn baz<R: std::io::Read>() ->Box<csv::Reader<R>>{
let mut rdr = ReaderBuilder::new().from_reader(std::io::stdin());
Box::new(rdr)
}
the error I'm getting:
Box::new(rdr)
| -------- ^^^ expected Reader<R>
, found Reader<Stdin>
| |
| arguments to this function are incorrect
|
= note: expected struct csv::Reader<R>
found struct csv::Reader<std::io::Stdin>
Surely, the R is not an R if you know what I mean but std::io::Stdin, that's why I've said that in the <...> brackets.
The key thing to understand here is that the generic arguments (R
in this case) are always chosen by the caller. In your first example, the function is designed to work with any type that implements Read
and therefore compiles.
The second, however, introduces a problem: According to the function signature, the caller should be able to get a Box<Reader<std::io::File>>
if that’s what they want. But the function body can only provide a Box<Reader<Stdin>>
.
3 Likes
Hi, thank you for your reply and clarifications.
So I've done this:
fn baz() ->csv::Reader<dyn std::io::Read>{
let mut rdr = ReaderBuilder::new().from_reader(std::io::stdin());
rdr
}
Also doesn't compile, and yet "it should"
Any ideas how to fix it?
dyn std::io::Read
is a dynamically-sized type (DST for short), it is a type itself, but in order to use DST, it needs a special ?Sized
bound. so by itself, the return type is already invalid, let alone the implementation returns a different type.
in your case, since you are returning a single concrete type (std::io::Stdin
), you should just spell the type directly.
if, for some reason, you are not willing to specify the actual type, you can use existential type (i.e. impl std::io::Read
), but not the trait object (i.e. dyn std::io::Read
).
Hi, but this is just an example. I want to be able to return different Readers, that is Readerstd::io::Stdin as well as Reader<&[u8]> etc
oh, I don't know what Reader<&[u8]>
is,I assume you mean Cursor<&[u8]>
, right? do you want something like this? note dyn SomeTrait
is DST, but Box<dyn SomeTrait>
is not.
fn baz(use_stdin: bool) ->csv::Reader<Box<dyn std::io::Read>>{
if use_stdin {
ReaderBuilder::new().from_reader(Box::new(std::io::stdin()))
} else {
ReaderBuilder::new().from_reader(Box::new(Cursor::new(&[12, 34, 56, 78])))
}
}
4 Likes
Thank you very much for your help. I thought that returning Box<Reader> would do the trick, but obviously it didn't.