首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >06-Rust 教程 - 结构体

06-Rust 教程 - 结构体

作者头像
LarryLan
发布2026-03-30 15:08:13
发布2026-03-30 15:08:13
740
举报

Rust 教程 - 结构体

结构体:数据的"收纳盒",把相关字段装一起


🎬 引入

你有没有写过这样的代码:

代码语言:javascript
复制
let user_name = "Alice";
let user_age = ;
let user_email = "alice@example.com";

三个变量,都表示同一个用户的信息,但它们之间没有任何关联。如果你想把这个用户传给一个函数,得传三个参数。如果你想存到数组里?抱歉,不行。

这时候就需要**结构体(Struct)**了。结构体就像是一个"数据收纳盒",把相关的字段打包在一起。从此以后,一个 User 就代表一个用户,清爽!

今天咱们就来聊聊 Rust 的结构体,看看它怎么帮你组织数据,以及它和其他语言的"类"有什么不一样。


📌 核心概念

结构体是什么?

结构体(Struct)是自定义的数据类型,用来把多个相关字段组合在一起。

生活化类比

  • 结构体 = 档案袋
  • 字段 = 档案里的表格(姓名、年龄、地址...)
  • 实例 = 具体的某个人档案

定义结构体:struct 关键字

代码语言:javascript
复制
struct User {
    username: String,
    email: String,
    age: u32,
    active: bool,
}

注意

  • 字段名和类型用冒号 : 隔开
  • 最后一个字段后面可以加分号(可选)
  • 字段默认是私有的(在模块外不可访问)

实例化:创建结构体

代码语言:javascript
复制
let user1 = User {
    username: String::from("alice"),
    email: String::from("alice@example.com"),
    age: ,
    active: true,
};

访问字段:用点号 .

代码语言:javascript
复制
println!("用户名:{}", user1.username);
println!("年龄:{}", user1.age);

更新语法:部分字段的"复制粘贴"

如果你想基于一个现有结构体创建新实例,只改几个字段,可以用更新语法

代码语言:javascript
复制
let user2 = User {
    username: String::from("bob"),
    ..user1  // 其他字段从 user1 复制
};

注意..user1 必须放在最后

代码语言:javascript
复制
// ✅ 正确
let user2 = User {
    username: String::from("bob"),
    ..user1
};

// ❌ 错误
let user2 = User {
    ..user1
    username: String::from("bob"),  // 编译错误
};

元组结构体:只要类型,不要字段名

有时候你只需要一个"有类型的元组",不需要字段名,这时候可以用元组结构体

代码语言:javascript
复制
struct Color(i32, i32, i32);
struct Point(i32, i32, i32);

let black = Color(, , );
let origin = Point(, , );

// 访问字段用索引
println!("R 分量:{}", black.);
println!("X 坐标:{}", origin.);

用途:给元组加"语义"。Color(0, 0, 0)(0, 0, 0) 更清楚这是颜色而不是坐标。

单元结构体:没有字段的结构体

代码语言:javascript
复制
struct Marker;

用途

  • 标记类型(用于泛型约束)
  • 实现 Trait 但不需要数据
  • 单例模式

方法:给结构体加"行为"

结构体不光能存数据,还能有方法(跟数据绑定的函数)。

代码语言:javascript
复制
impl User {
    fn greet(&self) {
        println!("你好,我是{}!", self.username);
    }
    
    fn have_birthday(&mut self) {
        self.age += ;
    }
}

调用方法

代码语言:javascript
复制
let mut user = User {
    username: String::from("alice"),
    email: String::from("alice@example.com"),
    age: ,
    active: true,
};

user.greet();           // 你好,我是 alice!
user.have_birthday();   // age 变成 26

self 参数:方法的"主人"

方法的第一参数通常是 self,有三种形式:

形式

含义

用途

&self

不可变借用

只读方法

&mut self

可变借用

修改数据

self

获取所有权

消耗掉结构体

代码语言:javascript
复制
impl User {
    // 只读
    fn get_username(&self) -> &str {
        &self.username
    }
    
    // 修改
    fn set_username(&mut self, new_name: String) {
        self.username = new_name;
    }
    
    // 消耗
    fn into_username(self) -> String {
        self.username  // 结构体被"拆解"了
    }
}

关联函数:不带 self 的"静态方法"

关联函数是没有 self 参数的方法,通常用作构造函数:

代码语言:javascript
复制
impl User {
    fn new(username: String, email: String) -> User {
        User {
            username,
            email,
            age: ,
            active: true,
        }
    }
}

// 调用
let user = User::new(
    String::from("alice"),
    String::from("alice@example.com"),
);

注意username, email字段初始化简写——当参数名和字段名相同时,可以省略 username: username


💻 代码示例

基础示例:完整的结构体

代码语言:javascript
复制
struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    // 关联函数(构造函数)
    fn new(width: u32, height: u32) -> Self {
        Rectangle { 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 main() {
    let rect1 = Rectangle::new(, );
    let rect2 = Rectangle::new(, );
    
    println!("面积:{}", rect1.area());  // 1500
    println!("能装下 rect2 吗?{}", rect1.can_hold(&rect2));  // true
}

错误示例 1:字段顺序错误

代码语言:javascript
复制
struct User {
    username: String,
    age: u32,
}

fn main() {
    let user = User {
        age: ,
        username: String::from("alice"),  // 顺序不同
    };
}

编译器错误

代码语言:javascript
复制
error[E0560]: struct `User` has no field named `username`
 --> src/main.rs:8:9
  |
8 |         username: String::from("alice"),
  |         ^^^^^^^^ help: a field with a similar name exists: `age`

人话翻译:等等...这个错误不对。实际上字段顺序可以不同。让我换个真正的错误。

代码语言:javascript
复制
struct User {
    username: String,
    age: u32,
}

fn main() {
    let user = User {
        username: String::from("alice"),
        // 忘记 age 字段
    };
}

编译器错误

代码语言:javascript
复制
error[E0063]: missing field `age` in initializer of `User`
 --> src/main.rs:7:16
  |
7 |     let user = User {
  |                ^^^^ missing `age`

人话翻译:编译器:"你说要创建 User,但 age 字段呢?别想蒙混过关!"

错误示例 2:修改不可变结构体

代码语言:javascript
复制
struct User {
    username: String,
    age: u32,
}

fn main() {
    let user = User {
        username: String::from("alice"),
        age: ,
    };
    
    user.age = ;  // 编译错误!
}

编译器错误

代码语言:javascript
复制
error[E0594]: cannot assign to `user.age`, as `user` is not declared as mutable
 --> src/main.rs:12:5
  |
12 |     user.age = 26;
  |     ^^^^^^^^^^^^^^ cannot assign
  |
help: consider changing this to be mutable
  |
5 |     let mut user = User {
  |         +++

人话翻译:编译器:"user 不是可变的,不能改!加个 mut 啊!"

错误示例 3:方法签名错误

代码语言:javascript
复制
struct User {
    username: String,
}

impl User {
    fn greet(self) {  // 用了 self,不是 &self
        println!("Hello, {}", self.username);
    }
}

fn main() {
    let user = User {
        username: String::from("alice"),
    };
    
    user.greet();
    user.greet();  // 编译错误:user 已经被移动了
}

编译器错误

代码语言:javascript
复制
error[E0382]: borrow of moved value: `user`
  --> src/main.rs:17:5
   |
12 |     let user = User { ... };
   |         ---- move occurs because `user` has type `User`, 
   |              which does not implement the `Copy` trait
13 |     user.greet();
   |     ----------- `user` moved due to this method call
...
17 |     user.greet();
   |     ^^^^ value borrowed here after move

人话翻译:编译器:"greet 方法拿走了 user 的所有权,第一次调用后 user 就没了。第二次调用?不存在的!"

修复:用 &self

代码语言:javascript
复制
fn greet(&self) {
    println!("Hello, {}", self.username);
}

🐛 常见坑点

坑点 1:忘记 mut

代码语言:javascript
复制
let user = User { ... };
user.age = ;  // 错误!

修复let mut user = User { ... };

坑点 2:所有权移动

代码语言:javascript
复制
struct User {
    name: String,
}

fn print_name(user: User) {
    println!("{}", user.name);
}

fn main() {
    let user = User { name: String::from("Alice") };
    print_name(user);
    print_name(user);  // 错误:user 已移动
}

修复:用借用。

代码语言:javascript
复制
fn print_name(user: &User) {
    println!("{}", user.name);
}

坑点 3:更新语法放错位置

代码语言:javascript
复制
let user2 = User {
    ..user1
    username: String::from("bob"),  // 错误!
};

修复..user1 必须放最后。

代码语言:javascript
复制
let user2 = User {
    username: String::from("bob"),
    ..user1
};

坑点 4:混淆 self 的三种形式

你想...

用这个

只读数据

&self

修改数据

&mut self

消耗/转换结构体

self


🎯 实战案例

案例 1:学生管理系统

代码语言:javascript
复制
struct Student {
    id: u32,
    name: String,
    grades: Vec<f32>,
}

impl Student {
    fn new(id: u32, name: String) -> Self {
        Student { id, name, grades: Vec::new() }
    }
    
    fn add_grade(&mut self, grade: f32) {
        self.grades.push(grade);
    }
    
    fn average(&self) -> f32 {
        if self.grades.is_empty() {
            return 0.0;
        }
        let sum: f32 = self.grades.iter().sum();
        sum / self.grades.len() as f32
    }
    
    fn is_passing(&self) -> bool {
        self.average() >= 60.0
    }
}

fn main() {
    let mut student = Student::new(, String::from("Alice"));
    student.add_grade(85.0);
    student.add_grade(92.0);
    student.add_grade(78.0);
    
    println!("平均分:{:.2}", student.average());
    println!("及格了吗?{}", if student.is_passing() { "✅" } else { "❌" });
}

案例 2:带调试输出的结构体

代码语言:javascript
复制
#[derive(Debug)]// 自动实现 Debug trait
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    let p = Point { x: , y:  };
    println!("{:?}", p);  // Point { x: 10, y: 20 }
    println!("{:#?}", p);  // 格式化输出
}

常用派生宏

  • #[derive(Debug)] - 调试输出
  • #[derive(Clone)] - 克隆
  • #[derive(Copy, Clone)] - 复制语义
  • #[derive(PartialEq, Eq)] - 比较
  • #[derive(Default)] - 默认值

案例 3:方法链(Builder 模式)

代码语言:javascript
复制
struct Request {
    url: String,
    method: String,
    headers: Vec<String>,
}

impl Request {
    fn new(url: String) -> Self {
        Request {
            url,
            method: String::from("GET"),
            headers: Vec::new(),
        }
    }
    
    fn method(mut self, method: String) -> Self {
        self.method = method;
        self
    }
    
    fn header(mut self, header: String) -> Self {
        self.headers.push(header);
        self
    }
    
    fn send(self) {
        println!("发送请求:{} {}", self.method, self.url);
        println!("Headers: {:?}", self.headers);
    }
}

fn main() {
    Request::new(String::from("https://api.example.com"))
        .method(String::from("POST"))
        .header(String::from("Content-Type: application/json"))
        .header(String::from("Authorization: Bearer token"))
        .send();
}

输出

代码语言:javascript
复制
发送请求:POST https://api.example.com
Headers: ["Content-Type: application/json", "Authorization: Bearer token"]

🧠 思维导图

06-结构体
06-结构体

📝 小结

  1. 结构体是自定义数据类型,把相关字段打包在一起
  2. 更新语法 ..other 必须放最后,其他字段从 other 复制
  3. 方法三种形式&self 只读,&mut self 修改,self 消耗
  4. 关联函数没有 self,常用作构造函数
  5. #[derive()] 自动实现常用 Trait,省事儿

下篇预告:结构体只能表示"是什么",那"有多种可能"怎么办?下一篇聊聊枚举与模式匹配,让你的代码能处理各种情况!


🔗 参考资料

  • Rust Book - 结构体
  • Rust By Example - 结构体
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-03-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Larry的Hub 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Rust 教程 - 结构体
    • 🎬 引入
    • 📌 核心概念
      • 结构体是什么?
      • 定义结构体:struct 关键字
      • 实例化:创建结构体
      • 更新语法:部分字段的"复制粘贴"
      • 元组结构体:只要类型,不要字段名
      • 单元结构体:没有字段的结构体
      • 方法:给结构体加"行为"
      • self 参数:方法的"主人"
      • 关联函数:不带 self 的"静态方法"
    • 💻 代码示例
      • 基础示例:完整的结构体
      • 错误示例 1:字段顺序错误
      • 错误示例 2:修改不可变结构体
      • 错误示例 3:方法签名错误
    • 🐛 常见坑点
      • 坑点 1:忘记 mut
      • 坑点 2:所有权移动
      • 坑点 3:更新语法放错位置
      • 坑点 4:混淆 self 的三种形式
    • 🎯 实战案例
      • 案例 1:学生管理系统
      • 案例 2:带调试输出的结构体
      • 案例 3:方法链(Builder 模式)
    • 🧠 思维导图
    • 📝 小结
    • 🔗 参考资料
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档