Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

rust 结构体(Struct)

结构体是 Rust 中自定义复合数据类型的基础工具。它将多个可能不同类型的值组合成一个有意义的整体,就像现实中的“表单”或“档案”。

1. 结构体是什么?有什么作用?

功能作用结构体允许你把相关的数据打包成一个新的类型。例如,描述一个“学生”需要姓名、年龄、学号等数据,结构体就能把这些字段捆绑在一起。这样做的好处是:

  • 代码更清晰,数据关系一目了然。
  • 可以针对这个结构体实现专属的行为(方法)。
  • 类型安全,编译器能帮你检查字段使用是否正确。

2. 结构体的基本规则(抽象结构)

// 定义结构体
struct 结构体名称 {
    字段名1: 类型1,
    字段名2: 类型2,
    ...
}

// 创建结构体实例-赋值(不可变)
let 实例 = 结构体名称 {
    字段名1: 值1,
    字段名2: 值2,
    ...
};

// 创建可变实例(可以修改字段)
let mut 实例 = 结构体名称 { ... };
实例.字段名1 = 新值;

// 访问字段
实例.字段名
  • 每个字段必须声明类型,字段之间用逗号分隔。
  • 默认情况下实例是不可变的,要修改字段需要将实例声明为 mut
  • 可以使用 结构体更新语法..other_instance)从另一个实例复制剩余字段。

3. 结构体示例

3.1 定义与实例化

// 定义一个用户结构体
struct User {
    username: String,
    email: String,
    active: bool,
    sign_in_count: u64,
}

fn main() {
    // 创建不可变实例
    let user1 = User {
        email: String::from("alice@example.com"),
        username: String::from("alice"),
        active: true,
        sign_in_count: 1,
    };
    println!("用户名: {}", user1.username);

    // 创建可变实例,并修改 email
    let mut user2 = User {
        email: String::from("bob@example.com"),
        username: String::from("bob"),
        active: false,
        sign_in_count: 0,
    };
    user2.email = String::from("bob_new@example.com");
    println!("新邮箱: {}", user2.email);
}

3.2 使用字段初始化简写

当函数参数名与结构体字段名相同时,可以省略重复:

#![allow(unused)]
fn main() {
fn build_user(email: String, username: String) -> User {
    User {
        email,      // 等价于 email: email
        username,   // 等价于 username: username
        active: true,
        sign_in_count: 1,
    }
}
}

3.3 结构体更新语法

从已有实例快速创建新实例,只修改部分字段:

#![allow(unused)]
fn main() {
let user3 = User {
    email: String::from("charlie@example.com"),
    ..user1   // 其余字段与 user1 相同(username、active、sign_in_count)
};
}

注意:更新语法会发生所有权的转移。如果原字段类型没有实现 Copy trait(如 String),原实例将不再可用(这里 user1username 被移动到了 user3)。


4. 为结构体定义方法(impl 块)

方法类似于其他语言的成员函数,定义在 impl 块中。第一个参数通常是 &self(不可变引用)、&mut self(可变引用)或 self(获取所有权)。

4.1 方法的基本规则

impl 结构体名称 {
    // 关联函数(没有 self 参数,通常用作构造器)
    fn 函数名(参数列表) -> Self { ... }

    // 实例方法(只读)
    fn 方法名(&self, 其他参数) -> 返回类型 { ... }

    // 实例方法(可修改)
    fn 方法名(&mut self, 其他参数) { ... }
}
  • Self(大写 S)是当前结构体类型的别名。
  • &selfself: &Self 的缩写,表示对实例的不可变引用。
  • 调用方法时使用点语法:实例.方法名()

4.2 方法示例

struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    // 关联函数:构造函数
    fn new(width: u32, height: u32) -> Self {
        Self { width, height }
    }

    // 实例方法:计算面积(只读)
    fn area(&self) -> u32 {
        self.width * self.height
    }

    // 实例方法:判断是否能容纳另一个矩形(只读)
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width >= other.width && self.height >= other.height
    }

    // 实例方法:放大两倍(修改自身)
    fn double(&mut self) {
        self.width *= 2;
        self.height *= 2;
    }
}

fn main() {
    let rect = Rectangle::new(30, 50);
    println!("面积: {}", rect.area());

    let mut rect2 = Rectangle::new(10, 20);
    rect2.double();
    println!("double 后宽度: {}", rect2.width);  // 20
}

5. 完整示例

下面的示例定义了一个 MyStruct 结构体,包含三个字段,并实现了关联函数 new 和实例方法 demo。最后在 demo 函数中演示了如何使用。

5.1 代码

#![allow(unused)]
fn main() {
// 定义一个结构体 MyStruct,包含 a、b、c 三个字段
// a、b 为整数类型,c 为字符串类型
struct MyStruct {
    a: i32,
    b: i32,
    c: String,
}

// impl 关键字用于给结构体实现方法
impl MyStruct {
    // 关联函数 new,用作构造函数
    // Self 关键字代表当前结构体类型(即 MyStruct)
    fn new() -> Self {
        Self {
            a: 0,
            b: 0,
            c: String::from("hello"),
        }
    }

    // 实例方法 demo
    // &self 表示当前结构体实例的不可变引用(类似于其他语言的 this)
    fn demo(&self) {
        let res = self.a + self.b;
        println!("res: {} , c: {}", res, self.c);
    }
}

pub fn demo() {
    println!("...............结构体示例开始.................");
    // 创建 MyStruct 实例,使用 :: 调用关联函数 new
    let ms = MyStruct::new();
    // 调用实例方法 demo
    ms.demo();
    println!("...............结构体示例结束.................");
}
}