尝试提供&[u8]
作为需要Read
的函数的参数似乎不像我预期的那样工作,如下面的示例所示。
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());
}
}
编译错误:
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
锈操场
以下特性实现可以在std::slice
文档中找到:
impl<'a> Read for &'a [u8]
.
我认为这是一个相当无益的错误消息。我来解释一下:
First:你不能有一个trait对象&Sized
。这违反了第一条对象安全规则,也没有真正的意义。添加Sized
特性绑定的唯一原因是使用所有Sized
类型的特殊属性(例如将其保存在堆栈上)。看看这个例子,它尝试使用属性:
fn foo(x: &Sized) {
let y = *x;
}
y
的尺寸是多少?与其他trait对象一样,编译器无法知道。所以我们不能将Sized
的唯一目的用于trait对象。因此,特性对象&Sized
是无用的,不能真正存在。
在这种情况下,错误信息至少告诉了我们正确的事情:
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`
此外:我怀疑您添加了+ Sized
绑定来解决相同的错误,该错误在您使用参数reader: &Read
时已经出现。下面是来自详细错误描述的一个重要见解:
一般来说,
Self : Sized
用来表示trait不应该作为trait对象使用。
对Read::bytes
的限制是有意义的,因为Bytes
迭代器对每个字节调用Read::read()
一次。如果这个函数调用是虚拟/动态的,那么函数调用的开销将远远高于read
处理字节的实际过程。
所以…为什么你需要把Read
作为一个trait对象呢?通常,通过泛型处理这个问题就足够了(而且在任何情况下都要快得多):
fn print_reader<R: Read>(reader: R) {
for byte in reader.bytes() {
println!("{}", byte.unwrap());
}
}
这避免了动态分派,并且可以很好地与类型检查器和优化器配合使用。