将数字基元(i32、f64 等)转换为字节表示

Converting number primitives (i32, f64, etc) to byte representations

我正在编写一个 encodes/decodes 数据 to/from 二进制格式的库。部分格式是数字,我使用 Rust 的原生原始类型(如 i8i64f32 等)。

是否有一种简单的内置方法可以将这些数据类型转换为 to/from 二进制,即转换 f64/f32/i64/等。变成 Vec<u8>?同样,有没有办法将 4 u8s(在 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_bitsfrom_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.