返回介绍

7.5 结构

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

三种结构体风格:

  • 命名结构:字段名。
  • 元组结构:命名元组。
  • 单元结构:不带任何字段。

命名结构

初始化必须是 {key:val, ...} ,除非是同名变量。必须包含全部字段。

添加 #[derive(Debug)] ,以便 {:?} 详细输出。字段默认为私有,外部模块访问需添加 pub

#[derive(Debug)]
struct Name {
  a: i64,
  b: i64,
  c: i64,
}

fn main() {
  let b = 3;
  let c = 4;
  let u = Name {a:1, b, c};   // 简写:b、c 字段值为同名变量或参数。

  let u2 = Name{
    c:10,
    ..u           // 更新:同类型其他变量更新(填充)其余字段。
  };
  
  assert_eq!(u2.a, u.a);
  assert_eq!(u2.b, u.b);
  assert_eq!(u2.c, 10);  
}
struct Point {
  x: i32,
  y: i32,
}

fn main() {
  let p = Point { x: 0, y: 7 };
  
  let Point { x: a, y: b } = p;  // 利用解构方式,定义变量 a、b。
  // let Point { x: a, .. } = p;   // 部分内容。

  assert_eq!(0, a);
  assert_eq!(7, b);
  
  let Point { x, y } = p;      // 与字段同名变量。
  // let Point { x, .. } = p;    
  
  assert_eq!(0, x);
  assert_eq!(7, y);    
}
struct Point {
  x: i32,
  y: i32,
}

fn main() {
  let p = Point { x: 6, y: 7 };
  let r = &p;

  assert_eq!(6, (*r).x);   
  assert_eq!(7, r.y);     // 操作符 “.” 隐式解引用。
}

不能标记局部字段可变。

可用 Cell 设定一个可变字段。

struct Point {
    x: i32,
  mut y: i32,   // 错误!不允许局部修改。
}

但可以有可变引用。

作为字段的引用本身不会改变,改变的是其引用的目标对象(mut)。目标对象不属于结构组成部分,自然不存在局部修改问题。

struct PointRef<'a> {
  x: &'a mut i32,
  y: &'a mut i32,
}

fn main() {
  let mut x = 10;
  let mut y = 20;

  let p = PointRef{x: &mut x, y: &mut y};
  
  *p.x = 100;  // p.x 访问字段,*(p.x) 透过字段访问外部变量。
  *p.y = 200;

  assert_eq!(x, 100);
  assert_eq!(y, 200);
}

对齐

编译器会对字段布局进行对齐(align)优化,减少内存占用。

use std::mem::size_of;

struct X {
  a: i32,
  b: i64,
  c: i32,
}

#[repr(C)]
struct Y {
  a: i32,
  b: i64,
  c: i32,
}

fn main() {
  assert_eq!(size_of::<X>(), 16);
  assert_eq!(size_of::<Y>(), 24);

  let x = X{a:1, b:2, c:3};
  let y = Y{a:1, b:2, c:3};

  // offset: 
  //   x.a - x > 0
  //   y.a - y == 0
  assert!(&x.a as *const i32 as usize - &x as *const X as usize > 0);
  assert!(&y.a as *const i32 as usize - &y as *const Y as usize == 0);
}

/*

(gdb) x/2xg &x
0x7fffffffe150:  0x0000000000000002  0x0000000300000001

(gdb) x/3xg &y
0x7fffffffe160:  0x0000000000000001  0x0000000000000002
0x7fffffffe170:  0x0000000000000003

*/

元组结构

元祖结构(tuple structs)有类型名,但字段没有,以序号访问。

#[derive(Debug)]
struct RGB(i32, i32, i32);

fn main() {
  let grey = RGB(119, 136, 153);
  
  println!("{:?}", grey);
  println!("{} {} {}", grey.0, grey.1, grey.2);
}
fn main() {
  let grey = RGB(119, 136, 153);
  let RGB(r, g, b) = grey;     // 解构,定义变量。

  assert_eq!(r, grey.0);
  assert_eq!(g, grey.1);
  assert_eq!(b, grey.2);
}

单元结构

单元结构(unit-like structs)没有字段,隐式定义了与类型同名的实例。

struct Electron;

等价于:

struct Electron {}           // 类型
Electron: Electron = Electron {};  // 实例

注意: struct T{}struct T 不同,缺了实例定义。

struct Y {}
struct X;

fn main() {
  let _a = X;
  let _b = Y;
       ^ use struct literal syntax instead: Y{}
}

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

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

发布评论

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