gpt4 book ai didi

rust - 为什么 Read::read 和 Read::read_exact 需要初始化传递给它们的缓冲区?

转载 作者:行者123 更新时间:2023-12-04 16:35:31 29 4
gpt4 key购买 nike

我有一个阅读器,其中包含有关 51*51 网格的信息,其中网格上的每个点都由 f32 表示。 .我想将这些数据读入一个向量,以便我可以轻松处理它:

pub fn from_reader<R: Read + Seek>(reader: &mut R) -> Arena {
let arena_size = 51 * 51;
let arena_byte_size = arena_size * size_of::<f32>();
let mut arena = vec![0.0f32; arena_size];

unsafe {
let mut arena_slice =
std::slice::from_raw_parts_mut(arena.as_mut_ptr() as *mut u8, arena_byte_size);
let _ = reader.read(&mut arena_slice);
};
//...
}
这种方法很不方便,而且速度太慢,因为它强制将向量的所有元素都初始化为 0 值。我原本想简单地分配一个缓冲区,而不是初始化它,将数据读入其中然后使用 from_raw_parts从中创建一个向量。但是我被告知这是未定义的行为,因为出于某种深不可测的原因, readread_exact要求调用者在调用它们中的任何一个之前初始化传递给它们的数据。
为什么会这样?有什么解决方法吗? Rust 团队是否正在研究任何解决方案?

最佳答案

Why is this the case?


因为它对 Read 的实现者有效首先读取传入的缓冲区。如果你传入了未初始化的数据和 Read 的实现者查看缓冲区,然后在纯安全代码中会有未定义的行为。从静态上看,不允许这样做是 Rust 的一大卖点。
use std::io::{self, Read};

struct Dummy;

impl Read for Dummy {
fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {
let v: u8 = buffer.iter().sum(); // Reading from the buffer
buffer[0] = v;
Ok(1)
}
}

fn main() {
let mut data = [0, 1, 2];
Dummy.read(&mut data).unwrap();
println!("{:?}", data);
}
  • 为什么Read::read不阻止从缓冲区读取 ?
    没有一种语言结构可以用来强加这种限制。与其他一些语言不同,Rust 没有“输出参数”。即使是这样,我也能看到 Read 的实现者希望能够读取它刚刚写入的数据。例如,一个阅读器计算通过它的换行符的数量。
  • 为什么Read::read不接受 MaybeUninit ?
    MaybeUninit 在 Rust 1.0 中不存在——它只在 Rust 1.36 中稳定下来。我们希望能够在 Rust 1.0 中读取文件。由于 Rust 的向后兼容性保证,现在无法更改方法的签名。
  • 为什么是 Read::read不是 unsafe ?
    这本来是支持未初始化数据的主要(唯一?)技术,但它会付出高昂的代价。 unsafe不是有经验的 Rust 程序员随便选择的工具。当我们确实使用它时,我们通常会非常努力地将其范围最小化。
    Read::read不安全,那么每个实现者都必须考虑如何正确满足不安全标准。这对“简单”适配器来说是一种沉重的负担。

  • Is there any workaround? Are there any solutions being worked on by the Rust team?


    不稳定 Read::initializer 方法是一种建议的解决方案,但它可能不是首选路线。
    RFC 2930提供了更新的尝试,并讨论了许多背景故事和挑战。
    也可以看看:
  • Is an array required to be initialized if I will read file contents into it?
  • In Rust, is there a way to directly read the content of a file into the given uninitialized byte array?
  • Is there a way to not have to initialize arrays twice?

  • 对于您的具体情况,您可能可以使用 Read::takeRead::read_to_end将您想要的所有字节读入空(未初始化!) Vec然后 convert a Vec<T> to a Vec<U> without copying the vector .您需要以某种方式确保已正确对齐 Vecf32因为它开始时只与 u8 对齐.

    关于rust - 为什么 Read::read 和 Read::read_exact 需要初始化传递给它们的缓冲区?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70220906/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com