【问题标题】:Trait objects, and reading n bytes into vector特征对象,并将 n 字节读入向量
【发布时间】:2015-07-24 05:29:03
【问题描述】:

假设我有以下,

use std::io;
use std::io::Read;

#[derive(Debug)]
enum FooReadError {
    UnexpectedEof,
    IoError(io::Error),
}

impl From<io::Error> for FooReadError {
    fn from(err: io::Error) -> FooReadError {
        FooReadError::IoError(err)
    }
}

fn read_n_bytes_to_vector<R: Read>(reader: &mut R, length: usize)
        -> Result<Vec<u8>, FooReadError> {
    let mut bytes = Vec::<u8>::with_capacity(length);
    unsafe { bytes.set_len(length); }
    let bytes_read = try!(reader.read(&mut bytes[..]));
    if bytes_read != length {
        Err(FooReadError::UnexpectedEof)
    } else {
        Ok(bytes)
    }
}

fn do_some_read(reader: &mut Read) -> Vec<u8> {
    read_n_bytes_to_vector(reader, 16).unwrap()
}

fn main() {
    let v = vec![0, 1, 2, 3, 4, 5];
    let mut cur = io::Cursor::<Vec<u8>>::new(v);
    do_some_read(&mut cur);
}

read_n_bytes_to_vector 应该获取任何实现 trait io::Read 的东西,从中读取 length 字节,并将它们放入一个向量中并返回该向量。

函数do_some_read 有一个io::Read 特征对象。那么,为什么呢:

% rustc ./vec_read.rs
./vec_read.rs:29:5: 29:27 error: the trait `core::marker::Sized` is not implemented for the type `std::io::Read` [E0277]
./vec_read.rs:29     read_n_bytes_to_vector(reader, 16).unwrap()
                     ^~~~~~~~~~~~~~~~~~~~~~
./vec_read.rs:29:5: 29:27 note: `std::io::Read` does not have a constant size known at compile-time
./vec_read.rs:29     read_n_bytes_to_vector(reader, 16).unwrap()
                     ^~~~~~~~~~~~~~~~~~~~~~

我同意 io::Read 不可能实现 Sized 的编译器;但我正在传递一个特征 object ——它们是恒定大小的,所以在这里应该没问题; **那么为什么会出现错误?* 但是等等,为什么它甚至很重要?该函数没有将 io::Read 用于 arg(对吗?),它也采用 trait 对象,因为 arg 是通用的,并且应该采用传入的完整类型。

【问题讨论】:

    标签: rust traits


    【解决方案1】:

    泛型包括默认绑定的Sized;如果您不希望它是必需的,则必须添加 ?Sized 绑定。

    一个特征对象是不是固定大小的; u16 as Trait 是两个字节,u32 as Trait 是四个字节,&c.;只有像 boxed trait 对象 (Box&lt;Trait&gt;) 和 trait 对象 references (&amp;Trait, &amp;mut Trait) 这样的东西具有恒定大小,在编译时已知(两个字对于引用的示例)。

    因为你只通过可变引用使用R,你可以添加?Sized绑定成功:

    fn read_n_bytes_to_vector<R: ?Sized + Read>(reader: &mut R, length: usize)
            -> Result<Vec<u8>, FooReadError> {
    

    【讨论】:

    • 阅读this,上面写着“特征对象,如&amp;FooBox&lt;Foo&gt;”让我相信它们的大小是恒定的(两个指针的大小,一个用于对象,一个用于 vtable)。那里的文档显示foo_obj as &amp;Trait 强制,但不显示foo_obj as Trait。后者有什么不同?另外,我不是在使用&amp;Foo,你说恒定大小的,那我为什么需要?Sized? (尽管如此,您的解决方案有效,但我想我无法解释为什么?)
    • This answer 似乎说了类似的话。如果我错了,请纠正我(测试我是否理解);请记住 Sized 默认情况下是泛型绑定的一部分(如您所说),在我的示例中,R&amp;mut Read 中的 only Read 匹配(&amp;mut 不属于限制,但 arg 中 R 的特定用途的一部分);所以RRead,但是R 需要满足Sized + ReadRead 当然不是。因此,我们需要选择退出 ?Sized。仍然好奇foo_type as Trait 做了什么/如果有的话?
    • (哎呀,那个文档对“特征对象”这个术语非常草率。)无法直接实例化未指定大小的类型;它们只能通过某种形式的间接创建,例如Box&lt;T&gt;&amp;T,因为大小不同。 foo as Trait 因此实际上并没有编译;我用它来表达指向的概念。这是一个有点复杂的主题,真的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-12
    • 1970-01-01
    • 2017-07-31
    • 2015-06-30
    相关资源
    最近更新 更多