结构体是 Rust 中自定义数据类型的核心方式之一。它允许你将多个相关的值组合成一个有意义的整体。


1. 结构体的定义与实例化

使用 struct 关键字定义结构体,每个字段都有名称和类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
// 定义结构体
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}

fn main() {
// 实例化结构体(必须为所有字段提供值)
let user1 = User {
username: String::from("zhangsan"),
email: String::from("zhangsan@example.com"),
sign_in_count: 1,
active: true,
};

// 访问字段使用点号
println!("用户名: {}", user1.username);
println!("邮箱: {}", user1.email);
println!("登录次数: {}", user1.sign_in_count);
println!("是否活跃: {}", user1.active);

// 可变结构体(整个实例必须是可变的,Rust不允许只标记某个字段为可变)
let mut user2 = User {
username: String::from("lisi"),
email: String::from("lisi@example.com"),
sign_in_count: 0,
active: false,
};
user2.email = String::from("lisi_new@example.com");
user2.sign_in_count += 1;
println!("修改后的邮箱: {}", user2.email);
}

2. 字段初始化简写(Field Init Shorthand)

当变量名与字段名相同时,可以使用简写语法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}

// 字段初始化简写:变量名与字段名相同时可以省略冒号和值
fn build_user(username: String, email: String) -> User {
User {
username, // 等价于 username: username
email, // 等价于 email: email
sign_in_count: 1,
active: true,
}
}

fn main() {
let user = build_user(
String::from("wangwu"),
String::from("wangwu@example.com"),
);
println!("用户: {}, 邮箱: {}", user.username, user.email);
}

3. 结构体更新语法(.. 运算符)

使用 .. 语法从已有实例创建新实例,未显式设置的字段将使用旧实例的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
struct User {
username: String,
email: String,
sign_in_count: u64,
active: bool,
}

fn main() {
let user1 = User {
username: String::from("zhangsan"),
email: String::from("zhangsan@example.com"),
sign_in_count: 1,
active: true,
};

// 使用结构体更新语法
// 只修改 email 和 username,其他字段来自 user1
let user2 = User {
email: String::from("lisi@example.com"),
username: String::from("lisi"),
..user1 // 剩余字段从 user1 中获取
};

// 注意:user1 中的 String 字段如果被移动到 user2,则 user1 不能再使用对应字段
// 但这里 username 和 email 都被显式设置了,..user1 只拷贝了 sign_in_count 和 active
// 这两个字段实现了 Copy trait,所以 user1 仍然可用
println!("user1 用户名: {}", user1.username);
println!("user2 用户名: {}, 邮箱: {}", user2.username, user2.email);
println!("user2 登录次数: {}", user2.sign_in_count); // 来自 user1

// 演示所有权移动的情况
let user3 = User {
email: String::from("new@example.com"),
..user1 // user1 的 username(String类型)被移动到 user3
};
// println!("{}", user1.username); // 编译错误!username 已被移动
// 但 user1.active 和 user1.sign_in_count 仍可访问(Copy类型)
println!("user1 仍可访问 active: {}", user1.active);
println!("user3 用户名: {}", user3.username);
}

4. 元组结构体(Tuple Struct)

元组结构体有结构体名称但字段没有名称,适合给元组起一个有意义的名字或区分类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// 元组结构体:字段没有名字,只有类型
struct Color(u8, u8, u8);
struct Point(f64, f64, f64);

// 即使字段类型完全相同,不同的元组结构体也是不同类型
struct Meters(f64);
struct Kilometers(f64);

fn main() {
let black = Color(0, 0, 0);
let red = Color(255, 0, 0);
let origin = Point(0.0, 0.0, 0.0);

// 使用索引访问字段
println!("红色: R={}, G={}, B={}", red.0, red.1, red.2);
println!("原点: ({}, {}, {})", origin.0, origin.1, origin.2);

// 解构元组结构体
let Color(r, g, b) = black;
println!("黑色: R={}, G={}, B={}", r, g, b);

// 类型安全:Meters 和 Kilometers 是不同类型
let distance = Meters(100.0);
let long_distance = Kilometers(5.0);
// let sum = distance.0 + long_distance.0; // 可以这样手动相加
println!("距离: {}m", distance.0);
println!("长距离: {}km", long_distance.0);

// 单字段元组结构体常用作 newtype 模式
struct Wrapper(Vec<String>);
let w = Wrapper(vec![String::from("hello"), String::from("world")]);
println!("包装器内容数量: {}", w.0.len());
}

5. 单元结构体(Unit Struct)

没有任何字段的结构体称为单元结构体,类似于空元组 ()。常用于实现某个 trait 但不需要存储数据的场景。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 单元结构体:没有字段
struct AlwaysEqual;

// 可以为单元结构体实现 trait
impl PartialEq for AlwaysEqual {
fn eq(&self, _other: &Self) -> bool {
true // 任何两个 AlwaysEqual 实例都相等
}
}

// 实际应用:用作标记类型(marker type)
struct Production;
struct Development;

trait Environment {
fn name(&self) -> &str;
fn is_debug(&self) -> bool;
}

impl Environment for Production {
fn name(&self) -> &str { "production" }
fn is_debug(&self) -> bool { false }
}

impl Environment for Development {
fn name(&self) -> &str { "development" }
fn is_debug(&self) -> bool { true }
}

fn print_env_info(env: &dyn Environment) {
println!("环境: {}, 调试模式: {}", env.name(), env.is_debug());
}

fn main() {
let a = AlwaysEqual;
let b = AlwaysEqual;
println!("a == b: {}", a == b);

let prod = Production;
let dev = Development;
print_env_info(&prod);
print_env_info(&dev);
}

6. 结构体的所有权

结构体可以拥有自己的数据,也可以引用外部数据(需要生命周期标注)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 结构体拥有自己的数据(推荐)
struct OwnedUser {
username: String, // String 是拥有所有权的类型
email: String,
}

// 结构体引用外部数据(需要生命周期标注)
struct BorrowedUser<'a> {
username: &'a str, // &str 是借用,需要生命周期
email: &'a str,
}

// 混合所有权
struct MixedUser<'a> {
username: String, // 拥有所有权
nickname: &'a str, // 借用
}

fn main() {
// 拥有所有权的结构体
let owned = OwnedUser {
username: String::from("zhangsan"),
email: String::from("zhangsan@example.com"),
};
println!("拥有数据: {}", owned.username);

// 借用数据的结构体
let name = String::from("lisi");
let email = String::from("lisi@example.com");
let borrowed = BorrowedUser {
username: &name,
email: &email,
};
println!("借用数据: {}", borrowed.username);
// name 和 email 在 borrowed 存活期间不能被修改或丢弃

// 混合所有权的结构体
let nick = String::from("小王");
let mixed = MixedUser {
username: String::from("wangwu"),
nickname: &nick,
};
println!("混合: {} ({})", mixed.username, mixed.nickname);
}

如果结构体中使用引用但不标注生命周期,编译器会报错:

1
2
3
4
5
// 以下代码无法编译!
// struct BadUser {
// username: &str, // 错误:缺少生命周期标注
// email: &str, // 错误:缺少生命周期标注
// }

7. 结构体的方法(impl 块)

使用 impl 块为结构体定义方法和关联函数。

7.1 &self&mut selfself

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#[derive(Debug)]
struct Rectangle {
width: f64,
height: f64,
}

impl Rectangle {
// &self:不可变借用,只读访问(最常用)
fn area(&self) -> f64 {
self.width * self.height
}

// &self:另一个只读方法
fn perimeter(&self) -> f64 {
2.0 * (self.width + self.height)
}

// &self:返回布尔值
fn is_square(&self) -> bool {
(self.width - self.height).abs() < f64::EPSILON
}

// &self:接受其他参数
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}

// &mut self:可变借用,可以修改字段
fn scale(&mut self, factor: f64) {
self.width *= factor;
self.height *= factor;
}

// &mut self:设置宽度
fn set_width(&mut self, width: f64) {
self.width = width;
}

// self:获取所有权,消耗原来的实例
fn into_square(self) -> Rectangle {
let side = self.width.max(self.height);
Rectangle {
width: side,
height: side,
}
}
}

fn main() {
let mut rect = Rectangle {
width: 30.0,
height: 50.0,
};

// 调用 &self 方法
println!("面积: {}", rect.area());
println!("周长: {}", rect.perimeter());
println!("是正方形吗: {}", rect.is_square());

let small = Rectangle { width: 10.0, height: 20.0 };
println!("rect 能包含 small 吗: {}", rect.can_hold(&small));

// 调用 &mut self 方法
rect.scale(2.0);
println!("缩放后面积: {}", rect.area());

rect.set_width(100.0);
println!("修改宽度后: {:?}", rect);

// 调用 self 方法(消耗 rect)
let square = rect.into_square();
println!("转为正方形: {:?}", square);
// println!("{:?}", rect); // 编译错误!rect 已被消耗
}

7.2 关联函数(没有 self 参数)

关联函数不以 self 作为第一个参数,类似于其他语言的静态方法。使用 :: 语法调用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#[derive(Debug)]
struct Circle {
center: (f64, f64),
radius: f64,
}

impl Circle {
// 关联函数:构造器(最常见的关联函数用途)
fn new(x: f64, y: f64, radius: f64) -> Self {
Circle {
center: (x, y),
radius,
}
}

// 关联函数:在原点创建
fn at_origin(radius: f64) -> Self {
Self::new(0.0, 0.0, radius)
}

// 关联函数:单位圆
fn unit() -> Self {
Self::at_origin(1.0)
}

// 普通方法
fn area(&self) -> f64 {
std::f64::consts::PI * self.radius * self.radius
}

fn circumference(&self) -> f64 {
2.0 * std::f64::consts::PI * self.radius
}
}

fn main() {
// 使用 :: 调用关联函数
let c1 = Circle::new(3.0, 4.0, 5.0);
let c2 = Circle::at_origin(10.0);
let c3 = Circle::unit();

println!("c1: {:?}, 面积: {:.2}", c1, c1.area());
println!("c2: {:?}, 周长: {:.2}", c2, c2.circumference());
println!("c3: {:?}, 面积: {:.4}", c3, c3.area());
}

7.3 多个 impl 块

一个结构体可以有多个 impl 块,在语义上没有区别。常用于分组相关方法或配合泛型、trait 实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#[derive(Debug)]
struct Calculator {
value: f64,
}

// 第一个 impl 块:构造和基本操作
impl Calculator {
fn new(value: f64) -> Self {
Calculator { value }
}

fn get_value(&self) -> f64 {
self.value
}
}

// 第二个 impl 块:算术操作
impl Calculator {
fn add(&mut self, n: f64) -> &mut Self {
self.value += n;
self
}

fn subtract(&mut self, n: f64) -> &mut Self {
self.value -= n;
self
}

fn multiply(&mut self, n: f64) -> &mut Self {
self.value *= n;
self
}

fn divide(&mut self, n: f64) -> &mut Self {
if n != 0.0 {
self.value /= n;
} else {
eprintln!("警告:除以零!");
}
self
}
}

// 第三个 impl 块:显示相关
impl Calculator {
fn display(&self) {
println!("当前值: {}", self.value);
}
}

fn main() {
let mut calc = Calculator::new(10.0);

// 链式调用
calc.add(5.0)
.multiply(2.0)
.subtract(3.0)
.divide(3.0);

calc.display(); // 当前值: 9.0
}

8. 结构体的打印

8.1 Debug trait

使用 #[derive(Debug)] 自动生成 Debug 实现,配合 {:?}{:#?} 格式化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 自动派生 Debug
#[derive(Debug)]
struct Point {
x: f64,
y: f64,
}

#[derive(Debug)]
struct Line {
start: Point,
end: Point,
color: String,
}

fn main() {
let p = Point { x: 1.0, y: 2.0 };
let line = Line {
start: Point { x: 0.0, y: 0.0 },
end: Point { x: 10.0, y: 10.0 },
color: String::from("red"),
};

// {:?} 单行 Debug 输出
println!("点: {:?}", p);

// {:#?} 美化的多行 Debug 输出
println!("线段:\n{:#?}", line);

// dbg! 宏:输出到 stderr,并返回值的所有权
let p2 = dbg!(Point { x: 3.0, y: 4.0 });
println!("dbg! 返回的值: {:?}", p2);

// dbg! 可以包裹表达式
let x = 5;
let y = dbg!(x * 2) + 1; // 输出: [src/main.rs:xx] x * 2 = 10
println!("y = {}", y); // y = 11
}

8.2 Display trait

手动实现 Display trait 以支持 {} 格式化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
use std::fmt;

struct Color {
r: u8,
g: u8,
b: u8,
}

// 手动实现 Display trait
impl fmt::Display for Color {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "#{:02X}{:02X}{:02X}", self.r, self.g, self.b)
}
}

// 同时实现 Debug(手动)
impl fmt::Debug for Color {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Color(r={}, g={}, b={})", self.r, self.g, self.b)
}
}

struct Matrix {
data: Vec<Vec<f64>>,
}

impl fmt::Display for Matrix {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for (i, row) in self.data.iter().enumerate() {
if i > 0 {
writeln!(f)?;
}
write!(f, "[")?;
for (j, val) in row.iter().enumerate() {
if j > 0 {
write!(f, ", ")?;
}
write!(f, "{:6.2}", val)?;
}
write!(f, "]")?;
}
Ok(())
}
}

fn main() {
let red = Color { r: 255, g: 0, b: 0 };
let teal = Color { r: 0, g: 128, b: 128 };

println!("Display: {}", red); // #FF0000
println!("Debug: {:?}", red); // Color(r=255, g=0, b=0)
println!("Teal: {}", teal); // #008080

let matrix = Matrix {
data: vec![
vec![1.0, 2.0, 3.0],
vec![4.0, 5.5, 6.0],
vec![7.0, 8.0, 9.99],
],
};
println!("矩阵:\n{}", matrix);
}

9. 结构体与派生宏

Rust 通过 #[derive(...)] 属性自动为结构体生成常用 trait 的实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// 常见的派生宏
#[derive(
Debug, // 调试输出 {:?}
Clone, // 深拷贝 .clone()
PartialEq, // 相等比较 ==、!=
Eq, // 完全相等(要求 PartialEq)
PartialOrd, // 部分排序 <、>、<=、>=
Ord, // 全排序(要求 Eq + PartialOrd)
Hash, // 可作为 HashMap 的键
)]
struct Student {
name: String,
age: u32,
grade: u32,
}

// Copy + Clone(仅适用于所有字段都实现了 Copy 的类型)
#[derive(Debug, Clone, Copy, PartialEq)]
struct Point {
x: f64,
y: f64,
}

// Default trait:提供默认值
#[derive(Debug, Default)]
struct Config {
width: u32,
height: u32,
title: String,
fullscreen: bool,
}

fn main() {
// Clone
let s1 = Student {
name: String::from("张三"),
age: 20,
grade: 3,
};
let s2 = s1.clone();
println!("s1: {:?}", s1);
println!("s2: {:?}", s2);

// PartialEq
println!("s1 == s2: {}", s1 == s2);

// Ord(排序)
let mut students = vec![
Student { name: String::from("王五"), age: 22, grade: 4 },
Student { name: String::from("张三"), age: 20, grade: 3 },
Student { name: String::from("李四"), age: 21, grade: 3 },
];
students.sort();
println!("排序后: {:#?}", students);

// Copy(赋值不会移动所有权)
let p1 = Point { x: 1.0, y: 2.0 };
let p2 = p1; // Copy,不是移动
println!("p1: {:?}, p2: {:?}", p1, p2); // p1 仍可用

// Default
let config = Config::default();
println!("默认配置: {:?}", config);

// 部分使用默认值
let custom_config = Config {
width: 1920,
height: 1080,
..Config::default()
};
println!("自定义配置: {:?}", custom_config);
}

10. 构建者模式(Builder Pattern)

构建者模式允许分步构建复杂对象,特别适合有很多可选参数的结构体。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#[derive(Debug)]
struct Server {
host: String,
port: u16,
max_connections: u32,
timeout_seconds: u64,
tls_enabled: bool,
log_level: String,
}

// 构建者结构体
struct ServerBuilder {
host: String,
port: u16,
max_connections: u32,
timeout_seconds: u64,
tls_enabled: bool,
log_level: String,
}

impl ServerBuilder {
// 创建构建者,提供必需参数和默认值
fn new(host: &str, port: u16) -> Self {
ServerBuilder {
host: host.to_string(),
port,
max_connections: 100, // 默认值
timeout_seconds: 30, // 默认值
tls_enabled: false, // 默认值
log_level: String::from("info"), // 默认值
}
}

// 每个方法设置一个选项,返回 self 支持链式调用
fn max_connections(mut self, max: u32) -> Self {
self.max_connections = max;
self
}

fn timeout(mut self, seconds: u64) -> Self {
self.timeout_seconds = seconds;
self
}

fn tls(mut self, enabled: bool) -> Self {
self.tls_enabled = enabled;
self
}

fn log_level(mut self, level: &str) -> Self {
self.log_level = level.to_string();
self
}

// 最终构建方法,消耗构建者生成目标对象
fn build(self) -> Server {
Server {
host: self.host,
port: self.port,
max_connections: self.max_connections,
timeout_seconds: self.timeout_seconds,
tls_enabled: self.tls_enabled,
log_level: self.log_level,
}
}
}

// 也可以直接在 Server 上提供 builder 关联函数
impl Server {
fn builder(host: &str, port: u16) -> ServerBuilder {
ServerBuilder::new(host, port)
}
}

fn main() {
// 使用默认配置
let server1 = Server::builder("localhost", 8080).build();
println!("服务器1: {:#?}", server1);

// 自定义配置(链式调用)
let server2 = Server::builder("0.0.0.0", 443)
.max_connections(1000)
.timeout(60)
.tls(true)
.log_level("debug")
.build();
println!("服务器2: {:#?}", server2);

// 只覆盖部分选项
let server3 = Server::builder("127.0.0.1", 3000)
.max_connections(50)
.build();
println!("服务器3: {:#?}", server3);
}

带验证的 Builder Pattern

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#[derive(Debug)]
struct Email {
from: String,
to: Vec<String>,
subject: String,
body: String,
}

#[derive(Debug)]
struct EmailBuilder {
from: Option<String>,
to: Vec<String>,
subject: Option<String>,
body: Option<String>,
}

impl EmailBuilder {
fn new() -> Self {
EmailBuilder {
from: None,
to: Vec::new(),
subject: None,
body: None,
}
}

fn from(mut self, from: &str) -> Self {
self.from = Some(from.to_string());
self
}

fn to(mut self, to: &str) -> Self {
self.to.push(to.to_string());
self
}

fn subject(mut self, subject: &str) -> Self {
self.subject = Some(subject.to_string());
self
}

fn body(mut self, body: &str) -> Self {
self.body = Some(body.to_string());
self
}

// build 返回 Result,如果缺少必需字段则返回错误
fn build(self) -> Result<Email, String> {
let from = self.from.ok_or("缺少发件人")?;
if self.to.is_empty() {
return Err("至少需要一个收件人".to_string());
}
let subject = self.subject.unwrap_or_else(|| "(无主题)".to_string());
let body = self.body.unwrap_or_default();

Ok(Email {
from,
to: self.to,
subject,
body,
})
}
}

fn main() {
// 正确构建
let email = EmailBuilder::new()
.from("sender@example.com")
.to("alice@example.com")
.to("bob@example.com")
.subject("会议通知")
.body("明天下午3点开会。")
.build();

match email {
Ok(e) => println!("邮件构建成功: {:#?}", e),
Err(err) => println!("构建失败: {}", err),
}

// 缺少收件人
let bad_email = EmailBuilder::new()
.from("sender@example.com")
.subject("测试")
.build();

match bad_email {
Ok(e) => println!("邮件: {:#?}", e),
Err(err) => println!("构建失败: {}", err),
}
}

总结

特性 说明
普通结构体 命名字段,最常用
元组结构体 无名字段,常用于 newtype 模式
单元结构体 无字段,用作标记类型
&self 不可变借用,只读
&mut self 可变借用,可修改
self 获取所有权,消耗实例
关联函数 self 参数,:: 调用
#[derive(...)] 自动生成 trait 实现
Builder 模式 分步构建复杂对象