将数字基元(i32、f64 等)转换为字节表示
Converting number primitives (i32, f64, etc) to byte representations
我正在编写一个 encodes/decodes 数据 to/from 二进制格式的库。部分格式是数字,我使用 Rust 的原生原始类型(如 i8
、i64
、f32
等)。
是否有一种简单的内置方法可以将这些数据类型转换为 to/from 二进制,即转换 f64
/f32
/i64
/等。变成 Vec<u8>
?同样,有没有办法将 4 u8
s(在 Vec<u8>
中)转换为 f32
?
不幸的是,目前 Rust 中没有对 reading/writing 原语 from/to 字节数组的安全内置支持。有几个社区图书馆,但是,byteorder 是最常用的:
extern crate byteorder;
use byteorder::{LittleEndian, WriteBytesExt};
use std::mem;
fn main() {
let i: i64 = 12345;
let mut bs = [0u8; mem::size_of::<i64>()];
bs.as_mut()
.write_i64::<LittleEndian>(i)
.expect("Unable to write");
for i in &bs {
println!("{:X}", i);
}
}
当然,您始终可以转换原始指针。比如可以把*const i64
转成*const i8
,然后转成合适的字节片&[u8]
。然而,这很容易出错,unsafe
并且由于字节顺序而依赖于平台,所以它应该只作为最后的手段使用:
use std::{mem, slice};
fn main() {
let i: i64 = 12345;
let ip: *const i64 = &i;
let bp: *const u8 = ip as *const _;
let bs: &[u8] = unsafe { slice::from_raw_parts(bp, mem::size_of::<i64>()) };
for i in bs {
println!("{:X}", i);
}
}
std::mem::transmute
可以用,虽然是unsafe
:
fn main() {
let var1 = 12345678_i64;
let raw_bytes: [i8; 8] = unsafe { std::mem::transmute(var1) };
for byte in &raw_bytes {
println!("{}", byte);
}
}
注意:请确保两个变量的大小完全相等。
如果您的目标是打印字节或将它们以 str
表示形式显示,只需在格式大括号
中使用 :b
表示法
fn main() {
println!("This is the binary of int {:b}", 4 as i32);
}
这会打印
This is the binary of int 100
从 Rust 1.32 开始,您可以对整数类型使用 {to,from}_{ne,le,be}_bytes
。
let begin = 1234_i32;
let bytes = begin.to_ne_bytes();
let and_back = i32::from_ne_bytes(bytes);
对于浮点数,您仍然必须依赖以前的方法。
Rust 1.40 有:{to,from}_{ne,le,be}_bytes
.
将数字转换为字节并返回(适用于 rust 1.40 之后的浮点数和整数):
let x = 65535_i32;
let x_bytes = x.to_be_bytes(); // x_bytes = [0, 0, 255, 255]
let original_x = i32::from_be_bytes(x_bytes); // original_x = 65535 = x
在 Rust 1.40 之前转换浮点数
Rust 1.32 具有:{to,from}_{ne,le,be}_bytes
(仅适用于整数)、to_bits
和 from_bits
.
将浮点数转换为字节并返回:
let y = 255.255_f32;
let y_bytes = y.to_bits().to_be_bytes();
let original_y = f32::from_bits(u32::from_be_bytes(y_bytes)); // original_y = 255.255 = y
根据 Rust 文档 from_bits
可以有 portability issues.
我正在编写一个 encodes/decodes 数据 to/from 二进制格式的库。部分格式是数字,我使用 Rust 的原生原始类型(如 i8
、i64
、f32
等)。
是否有一种简单的内置方法可以将这些数据类型转换为 to/from 二进制,即转换 f64
/f32
/i64
/等。变成 Vec<u8>
?同样,有没有办法将 4 u8
s(在 Vec<u8>
中)转换为 f32
?
不幸的是,目前 Rust 中没有对 reading/writing 原语 from/to 字节数组的安全内置支持。有几个社区图书馆,但是,byteorder 是最常用的:
extern crate byteorder;
use byteorder::{LittleEndian, WriteBytesExt};
use std::mem;
fn main() {
let i: i64 = 12345;
let mut bs = [0u8; mem::size_of::<i64>()];
bs.as_mut()
.write_i64::<LittleEndian>(i)
.expect("Unable to write");
for i in &bs {
println!("{:X}", i);
}
}
当然,您始终可以转换原始指针。比如可以把*const i64
转成*const i8
,然后转成合适的字节片&[u8]
。然而,这很容易出错,unsafe
并且由于字节顺序而依赖于平台,所以它应该只作为最后的手段使用:
use std::{mem, slice};
fn main() {
let i: i64 = 12345;
let ip: *const i64 = &i;
let bp: *const u8 = ip as *const _;
let bs: &[u8] = unsafe { slice::from_raw_parts(bp, mem::size_of::<i64>()) };
for i in bs {
println!("{:X}", i);
}
}
std::mem::transmute
可以用,虽然是unsafe
:
fn main() {
let var1 = 12345678_i64;
let raw_bytes: [i8; 8] = unsafe { std::mem::transmute(var1) };
for byte in &raw_bytes {
println!("{}", byte);
}
}
注意:请确保两个变量的大小完全相等。
如果您的目标是打印字节或将它们以 str
表示形式显示,只需在格式大括号
:b
表示法
fn main() {
println!("This is the binary of int {:b}", 4 as i32);
}
这会打印
This is the binary of int 100
从 Rust 1.32 开始,您可以对整数类型使用 {to,from}_{ne,le,be}_bytes
。
let begin = 1234_i32;
let bytes = begin.to_ne_bytes();
let and_back = i32::from_ne_bytes(bytes);
对于浮点数,您仍然必须依赖以前的方法。
Rust 1.40 有:{to,from}_{ne,le,be}_bytes
.
将数字转换为字节并返回(适用于 rust 1.40 之后的浮点数和整数):
let x = 65535_i32;
let x_bytes = x.to_be_bytes(); // x_bytes = [0, 0, 255, 255]
let original_x = i32::from_be_bytes(x_bytes); // original_x = 65535 = x
在 Rust 1.40 之前转换浮点数
Rust 1.32 具有:{to,from}_{ne,le,be}_bytes
(仅适用于整数)、to_bits
和 from_bits
.
将浮点数转换为字节并返回:
let y = 255.255_f32;
let y_bytes = y.to_bits().to_be_bytes();
let original_y = f32::from_bits(u32::from_be_bytes(y_bytes)); // original_y = 255.255 = y
根据 Rust 文档 from_bits
可以有 portability issues.