mem::transmute() 函数

这个函数用于将一个值从当前类型转换成另一种类型. 类似于C语言中的强制类型转换. 要注意的是, 源类型与目标类型应该大小相同.

use std::mem;

fn main() {
    let pack: [u8; 4] = [0x01, 0x02, 0x03, 0x04];
    let pack_u32 = unsafe { mem::transmute::<[u8; 4], u32>(pack) };
    assert_eq!(pack_u32, 0x04030201);
}

相同的功能, 用C语言实现:

#include <stdint.h>
#include <stdlib.h>
#include <assert.h>

int main() {
  uint8_t pack[4] = {0x01, 0x02, 0x03, 0x04};
  uint32_t pack_u32 = *(uint32_t*)pack;
  assert(pack_u32 == 0x04030201);

  return 0;
}

将枚举转换为 u8

用这个函数也可以将枚举结构中的签标 tag 值转为 u8 或者别的整数类型:

use std::mem;

#[derive(Debug, Clone, Copy)]
pub enum Shape {
    Rectangle,
    Circle,
    Ellipse,
}

impl Shape {
    pub fn tag(&self) -> u8 {
        unsafe { mem::transmute(*self) }
    }
}

fn main() {
    let c = Shape::Circle;
    println!("c.tag() is {}", c.tag());
}

手动构造切片引用

切片引用本身就是一个胖指针:

  • data ptr: 指向切片元素的起始内存
  • len: 切片中元素的个数
use std::mem;

fn main() {
    let nums = [0_i32, 1, 2, 3];

    let slice: &[i32] = unsafe {
        let nums_addr: usize = nums.as_ptr() as usize;
        let len = nums.len();
        mem::transmute([nums_addr, len])
    };
    assert_eq!(slice.len(), 4);
    assert_eq!(slice[2], 2);
    assert_eq!(slice[3], 3);
}

其它转换方式