在 JavaScript 中,当您需要通过以下方式访问内存块时,将使用 DataView
:
- 不同的宽度类型(
uint8
、uint16
、uint32
、float32
等) - 未对齐的数据
- 特定的字节顺序
DataView
通常用于网络代码、解析和创建二进制文件格式以及实现虚拟机。虽然前两个只能进行顺序访问,但使用 DataView 作为 RAM 的虚拟机需要能够自由访问(甚至随机!)
最佳答案
作为一种系统语言,Rust 本身就有能力与原始内存交互,而不需要特定的包装器。
因此,阅读 u32
内存不足只需要少量 unsafe
:
fn read_u32(bytes: &[u8]) -> u32 {
assert!(bytes.as_ptr() as usize % std::mem::align_of::<u32>() == 0);
assert!(bytes.len() >= 4);
unsafe { *(bytes.as_ptr() as *const u32) }
}
这种原始能力可用于构建更好的抽象。值得注意的是,抽象负责处理对齐和字节顺序。
byteorder
crate 提供了这样的抽象:LitteEndian
和BigEndian
类型都实现 ByteOrder
特质。
上述函数可以改进为:
fn read_u32(bytes: &[u8]) -> u32 { LittleEndian::read_u32(bytes) }
它将负责:
- 正在执行转换。
- 均匀地处理未对齐的访问,而不是出现 panic 。
- 具有明确的字节顺序。
不过,它实际上只考虑了原始类型,这就是 bytes
的位置。 crate 介入。
例如,让我们解码 UDP Header :
use std::io::Cursor;
use bytes::buf::Buf;
struct UdpHeader {
src_port: u16,
dst_port: u16,
length: u16,
checksum: u16,
}
fn read_udp_header<T: AsRef<[u8]>>(bytes: &mut Cursor<T>) -> UdpHeader {
UdpHeader {
src_port: bytes.read_u16_be(),
dst_port: bytes.read_u16_be(),
length: bytes.read_u16_be(),
checksum: bytes.read_u16_be(),
}
}
它使用 Cursor
标准库中的结构及其 Buf
的实现来自bytes
的特征.
您可以在从内存任意点开始的 byte slice ( &[u8]
) 周围创建光标;读取它会推进它,为下一次读取定位它,它将处理对齐、字节序和边界检查。
注意:不幸的是,似乎没有版本返回 Option<u16>
;如果这是一个问题,我可能会延长它。
因此,我认为您对列出的 crate 有正确的想法,它们涵盖了您提出的所有要求。
关于rust - Rust 中 JavaScript 的 DataView 相当于什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53137252/