我有一个阅读器,其中包含有关 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);
};
//...
}
Run Code Online (Sandbox Code Playgroud)
此方法不方便且不必要地缓慢,因为它强制向量的所有元素都使用 0 值进行初始化。我最初想简单地分配一个缓冲区,而不是初始化它,将数据读入其中,然后用from_raw_parts
它来创建一个向量。然而,我被告知这是未定义的行为,因为出于某种难以理解的原因,read
并且read_exact
要求调用者在调用它们中的任何一个之前初始化传递给它们的数据。
为什么会这样呢?有什么解决方法吗?Rust 团队正在研究任何解决方案吗?
\n\n为什么会这样呢?
\n
Read
因为对于 的实现者来说,首先读取传入的缓冲区是有效的。如果您传入未初始化的数据和实现者Read
查看缓冲区,那么纯安全代码中将会出现未定义的行为。静态地禁止这种情况是 Rust 的一大卖点。
use std::io::{self, Read};\n\nstruct Dummy;\n\nimpl Read for Dummy {\n fn read(&mut self, buffer: &mut [u8]) -> io::Result<usize> {\n let v: u8 = buffer.iter().sum(); // Reading from the buffer\n buffer[0] = v;\n Ok(1)\n }\n}\n\nfn main() {\n let mut data = [0, 1, 2];\n Dummy.read(&mut data).unwrap();\n println!("{:?}", data);\n}\n
Run Code Online (Sandbox Code Playgroud)\n为什么不Read::read
阻止从缓冲区读取?
没有可用于施加该限制的语言结构。与其他一些语言不同,Rust 没有“输出参数”。即使确实如此,我也可以看到一个实现者Read
希望能够读取它刚刚需要的数据。例如,一个读取器计算通过它的换行符的数量。
为什么不Read::read
接受MaybeUninit
?
MaybeUninit
Rust 1.0 \xe2\x80\x94 中不存在,仅在 Rust 1.36 中稳定。我们希望能够在 Rust 1.0 中读取文件。由于 Rust 的向后兼容性保证,该方法的签名现在无法更改。
为什么Read::read
不是unsafe
?
这将是支持未初始化数据的主要(唯一?)技术,但成本很高。unsafe
这不是经验丰富的 Rust 程序员会轻易选择的工具。当我们确实使用它时,我们通常会努力缩小其范围。
如果Read::read
不安全,那么每个实施者都必须考虑如何正确满足不安全标准。这对“简单”适配器来说是一个沉重的负担。
\n\n有什么解决方法吗?Rust 团队正在研究任何解决方案吗?
\n
不稳定Read::initializer
方法是一种建议的解决方案,但它可能不是首选途径。
RFC 2930提供了更新的尝试,并讨论了许多背景故事和挑战。
\n也可以看看:
\n\n对于您的具体情况,您可能可以使用Read::take
和Read::read_to_end
将您想要的所有字节读入空(未初始化!)Vec
,然后将 a 转换Vec<T>
为 aVec<U>
而不复制向量。您需要以某种方式确保您已正确对齐Vec
for f32
,因为它一开始仅与 for 对齐u8
。
归档时间: |
|
查看次数: |
1112 次 |
最近记录: |