返回介绍

7.6 联合

发布于 2024-10-13 11:25:30 字数 1537 浏览 0 评论 0 收藏 0

不同于结构体字段各自拥有独立的内存地址和存储空间,联合(union)各字段共享内存地址和存储空间。简单点说,就是同一块内存,以不同视角(field type)进行读写。

  • 尺寸由长度最大的字段类型决定。
  • 默认各字段起始地址相同。
  • 初始化表达式只能有一个字段。
  • 共享内存,对字段操作是不安全的(unsafe)。
use std::mem::size_of_val;

union Data {
  int: i32,
  byte: u8,
}

fn main() {
  let d = Data{ int: 0 };
  
  unsafe {
    // 尺寸由长度最大的字段决定。
    assert_eq!(size_of_val(&d), size_of_val(&d.int));

    // 各字段共享内存和起始地址。
    let p1: *const i32 = &d.int;
    let p2: *const u8 = &d.byte;
    assert_eq!(p1 as usize, p2 as usize);    
  }
}

以不同字段视角去读写联合体内存。

union Data {
  int: i32,
  bytes: [u8; 4],
}

fn main() {
  let mut d = Data{ int: 0x112233 };
  
  unsafe {
    // 以另一个字段的视角读取内存。
    assert_eq!(d.bytes, [0x33, 0x22, 0x11, 0]);

    // 以另一个字段修改数据。
    d.bytes[1] = 0x55;
    assert_eq!(d.int, 0x115533);
  }
}

匹配操作与结构体类似。

union Data {
  int: i32,
  bytes: [u8; 4],
}

fn main() {
  let d = Data{ int: 0x112233 };
  
  unsafe {
    match d {
      Data { int: 0x1122 } => { println!("int: {:x}", d.int); }
      Data { bytes } => { println!("bytes: {:#?}", bytes); }
    }
  }
}

因各字段共享内存,对一个字段进行可变引用,就相当于其他字段也处于可变引用状态。

fn main() {
  let mut d = Data{ int: 0x112233 };
  
  unsafe {
    let a = &mut d.int;
        ---------- first mutable borrow occurs here (via `d.int`)

    let b = &mut d.bytes;
        ^^^^^^^^^^^^ second mutable borrow occurs here (via `d.bytes`)

    *a += 1;
    ------- first borrow later used here
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文