Reputation: 881
Trying to provide &[u8]
as argument to a function requiring Read
doesn't seem to work as I expected, as illustrated by the below example.
use std::io::Read;
fn main() {
let bytes: &[u8] = &[1, 2, 3, 4];
print_reader(&bytes);
}
fn print_reader(reader: &(Read + Sized)) {
for byte in reader.bytes() {
println!("{}", byte.unwrap());
}
}
Compiler error:
error: the trait bound `std::io::Read + Sized: std::marker::Sized` is not satisfied [--explain E0277]
--> <anon>:9:24
9 |> for byte in reader.bytes() {
|> ^^^^^
note: `std::io::Read + Sized` does not have a constant size known at compile-time
error: the trait bound `std::io::Read + Sized: std::marker::Sized` is not satisfied [--explain E0277]
--> <anon>:9:5
9 |> for byte in reader.bytes() {
|> ^
note: `std::io::Read + Sized` does not have a constant size known at compile-time
note: required because of the requirements on the impl of `std::iter::Iterator` for `std::io::Bytes<std::io::Read + Sized>`
error: aborting due to 2 previous errors
The following trait implementation can be found in the std::slice
documentation:
impl<'a> Read for &'a [u8]
.
Upvotes: 2
Views: 717
Reputation: 88636
I think this is a rather an unhelpful error message. I'll try to explain:
First: you can't have a trait object &Sized
. This violates the first object safety rule and it doesn't really make sense either. The only reason to add the Sized
trait bound is to use the special property of all Sized
types (e.g. saving it on the stack). Look at this example trying to use the property:
fn foo(x: &Sized) {
let y = *x;
}
What size would y
have? The compiler can't know, as with any other trait object. So we're not able to use the only purpose of Sized
with trait objects. Thus a trait object &Sized
is useless and can't really exist.
In this case the error message at least kind of tells us the correct thing:
error: the trait `std::marker::Sized` cannot be made into an object [--explain E0038]
--> <anon>:7:1
7 |> fn foo(x: &Sized) {
|> ^
note: the trait cannot require that `Self : Sized`
Furthermore: I suspect you added the + Sized
bound to work around the same error, which already showed up when you had the argument reader: &Read
. Here is one important insight from the detailed error description:
Generally,
Self : Sized
is used to indicate that the trait should not be used as a trait object.
This restriction for Read::bytes
does make sense, because the Bytes
iterator calls Read::read()
once for every single byte. If this function call would be a virtual/dynamic one, the overhead for the function call would be much higher than the actual process of read
ing the byte.
So... why do you need to have Read
as a trait object anyway? Often it's sufficient (and in any case much faster) to handle this via generics:
fn print_reader<R: Read>(reader: R) {
for byte in reader.bytes() {
println!("{}", byte.unwrap());
}
}
This avoids dynamic dispatch and works nicely with the type checker and the optimizer.
Upvotes: 2