自定义类型:结构体

原理

struct 在编译后对应连续内存布局(C 兼容的 repr)。Rust 默认不保证字段顺序(可重排以优化对齐填充),但 #[repr(C)] 可锁定为 C 兼容布局。

栈上结构体内存:struct { x: i32, y: f64 } 对齐后为 16 字节(4B x + 4B padding + 8B y)。#[derive(Debug)] 通过过程宏自动生成 fmt::Debug trait 实现,不增加运行时开销。

impl 块的 &self 参数在编译后对应一个隐式指针参数(等价于 C 的 this 指针)。关联函数(无 &self)是普通的命名空间函数,调用方式 Type::func()

元组结构体 struct Point(i32, i32) 和普通同名结构体是不同的类型,不能互换。单元结构体 struct Unit; 实例大小为 0 字节(零大小类型 ZST),编译器优化后不留内存痕迹。

C: 结构体


语法

定义与实例化

#[derive(Debug)]
struct Person {
    name: String,
    age: u32,
}
 
let mut p = Person {
    name: String::from("小明"),
    age: 18,
};
p.age = 19;                       // 需要 mut

字段初始化简写

let name = String::from("小明");
let age = 18;
let p = Person { name, age };     // 变量名==字段名时可省略

结构体更新语法

let p2 = Person {
    name: String::from("小红"),
    ..p1   // 其余字段从 p1 移动(Copy 字段复制)
};
// 非 Copy 字段被移动后 p1 不可再用

方法(impl 块)

impl Person {
    // 实例方法:&self / &mut self / self
    fn greet(&self) {
        println!("我叫{}", self.name);
    }
 
    fn birthday(&mut self) {
        self.age += 1;
    }
 
    // 关联函数(构造器模式)
    fn new(name: String, age: u32) -> Self {
        Person { name, age }
    }
}
 
let p = Person::new(String::from("小红"), 17);
p.greet();

结构体三种形式

形式语法访问
普通struct P { x: i32 }p.x
元组struct P(i32, f64)p.0, p.1
单元struct P;无字段

Debug 打印

#[derive(Debug)]
struct P { x: i32 }
let p = P { x: 5 };
println!("{:?}", p);     // P { x: 5 }
println!("{:#?}", p);    // 美化输出

实践

力扣问题

力扣: 力扣数组题 — 结构体排序

#[derive(Debug)]
struct Student {
    name: String,
    ch: i32, ma: i32, en: i32,
}
 
fn main() {
    // 读入n个学生,按总分排序输出
}

AI 自检

  1. impl<T> Point<T>impl<T> 为何必须写?<T> 的作用域是什么?
  2. ZST(零大小类型)如 struct Unit; 的实例大小为多少?编译器如何优化?