施放& [u8]到std :: io :: Read导致大小问题

时间:2016-08-11 20:11:12

标签: casting rust traits

尝试将&[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

Rust playground

可以在std::slice文档中找到以下特征实现:

impl<'a> Read for &'a [u8]

1 个答案:

答案 0 :(得分:2)

认为这是一个相当无用的错误消息。我试着解释一下:

首先:您不能拥有特征对象&Sized。这违反了first object safety rule,它也没有任何意义。添加Sized特征限制的唯一原因是使用所有Sized类型的特殊属性(例如,将其保存在堆栈中)。看看这个例子试图使用属性:

fn foo(x: &Sized) {
    let y = *x;
}

y的大小是多少?编译器不能像任何其他特征对象那样知道。因此,我们无法将Sized的唯一目的用于特征对象。因此,特质对象&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用于表示特征不应用作特征对象。

Read::bytes的这个限制确实有意义,因为Bytes迭代器会为每个字节调用Read::read()一次。如果此函数调用是虚拟/动态调用,则函数调用的开销将远远高于read字节的实际过程。

所以...... 为什么你需要将Read作为特征对象呢?通过泛型来处理这个问题通常是足够的(并且在任何情况下要快得多):

fn print_reader<R: Read>(reader: R) {
    for byte in reader.bytes() {
        println!("{}", byte.unwrap());
    }
}

这可以避免动态调度,并且可以与类型检查器优化器一起使用。