09.Struct
结构体的命名规则一般遵循 PascalCase 模式。
PascalCase 模式:各单词首字母大写,单词之间没有空格或下划线。
结构体的定义
rust
struct User {
email: String,
username: String,
active: bool,
sign_in_count: u64,
}每个字段包含一个名称和类型。只有当结构体被声明后,后续才能够使用该结构体,使用结构体的例子如下:
rust
let mut user1 = User {
email: String::from("someone@example.com"),
username: String::from("admin123"),
active: true,
sign_in_count: 1,
};可以直接修改结构体中某字段的值(前提是定义的结构体是可变类型),使用点式访问法访问结构体中的字段:
rust
user1.email = String::from("someone@outlook.com");结构体的应用
函数返回结构体
写一个函数,返回的值是结构体:
rust
fn build_user(email: String, username: String) -> User {
User {
email,
username,
active: true,
sign_in_count: 1,
}
}注意,当原本的结构体的字段名称和值(来自函数的参数)的名称相同时,可以直接写函数的参数:

如果除了某个字段(如 email)外,其他字段都和某个结构体相同,则以下是简便的声明方法:
rust
let mut user2 = User {
email: String::from("someone@123.com"),
..user1 // user1 的 email 字段被 user2 覆盖
};如果使用上述的声明方法,则:
- 使用
..user1,user1的字段的所有权会被转移给user2(除非实现了 Copy trait)。 - 转移是完全的,
user1现在不能再访问这些字段。 - 对于
email字段,由于在user2中提前定义了email字段,因此在执行..user1时,user1的email字段的所有权不会被转移,后续仍可通过user1.email访问user1的email字段。
结构体的借用
案例:
rust
struct Point {
x: i32,
y: i32,
z: i32,
}
fn main() {
let mut p = Point { x: 1, y: 2, z: 3 };
let x = &mut p.x; // 执行此行完毕后,p 失去所有权限(包括读)
// print_point(&p); // 此处传入的是不可变引用,rust 不允许变量同时拥有可变和不可变引用
// 此时 p 中元素已被可变借用,因此 p 不可再被借用,即使是可变借用也不行
p.y = 3; // 但 p 中的其他元素可以被访问,因为只存在对 x 的借用,不会影响其他元素
*x += 1;
print_point(&p); // 所有借用使用完毕,可以对 p 进行借用
}
fn print_point(p: &Point) {
println!("{}, {}, {}", p.x, p.y, p.z);
}输出:
2, 3, 3Tuple Struct
元组结构体,字段只有类型,没有名称,声明如下:
rust
struct Color(i32, i32, i32);
let black = Color(0, 0, 0);打印结构体
打印结构体需要对结构体开启 debug 模式,然后占位符使用 :? ,如下:
rust
#[derive(Debug)]
struct User {
email: String,
username: String,
active: bool,
sign_in_count: u64,
}
println!("结构体 user2:\n{:?}", user2);
println!("美化结构体打印 user2:\n{user2:#?}"); // 在 : 和 ? 之间加上 #输出:
结构体 user2:
User { email: "someone@123.com", username: "admin123", active: true, sign_in_count: 1 }
美化结构体打印 user2:
User {
email: "someone@123.com",
username: "admin123",
active: true,
sign_in_count: 1,
}重点习题讲解
习题 1
以下代码能否通过编译?
rust
struct Point3 {
x: i32,
y: i32,
}
impl Point3 {
fn get_x(&mut self) -> &mut i32 {
&mut self.x
}
}
let mut p2 = Point3 { x: 1, y: 2 };
let x = p2.get_x();
*x += 1;
println!("{} {}", *x, p2.y);解答:
不能,因为当 x 通过 get_x() 方法获得 p2 中的 x 的可变借用时,由于 rust 的安全机制,其借用规则认为整个 p2 都被借用了(即使实际上只借用了其中的一个字段),因此在可变借用 x 的生命周期内,也不能对 p2 的其他部分(比如 p2.y)进行任何访问。
后续的 println! 中使用到了 x ,说明可变借用 x 的作用域还未结束,则此时也不能访问 p2 中的其他元素。