自定义类型:结构体
原理
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),编译器优化后不留内存痕迹。
语法
定义与实例化
#[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 自检
impl<T> Point<T>中impl<T>为何必须写?<T>的作用域是什么?- ZST(零大小类型)如
struct Unit;的实例大小为多少?编译器如何优化?