Skip to content

实战总结

> 综合运用结构体知识,学习派生 Trait、常见错误诊断与调试技巧。

派生 Trait

常用派生宏

rust
// Debug - 调试输出
#[derive(Debug)]
struct Person {
    name: String,
    age: u32,
}

// Clone - 克隆
#[derive(Clone)]
struct Data {
    value: i32,
}

// Copy - 复制(只适用于栈上类型)
#[derive(Copy, Clone)]
struct Point {
    x: i32,
    y: i32,
}

// PartialEq - 相等比较
#[derive(PartialEq)]
struct Color(u8, u8, u8);

// Eq - 完全相等(需要 PartialEq)
#[derive(PartialEq, Eq)]
struct Id(u32);

// PartialOrd - 部分排序
#[derive(PartialEq, PartialOrd)]
struct Score(f64);

// Ord - 完全排序(需要 PartialEq, Eq, PartialOrd)
#[derive(PartialEq, Eq, PartialOrd, Ord)]
struct Rank(u32);

// Hash - 哈希
#[derive(PartialEq, Eq, Hash)]
struct Key(String);

// 组合派生
#[derive(Debug, Clone, PartialEq, Eq)]
struct User {
    id: u32,
    name: String,
}
▶ Run

使用派生 Trait

rust
#[derive(Debug, Clone, PartialEq)]
struct Person {
    name: String,
    age: u32,
}

fn main() {
    let p1 = Person {
        name: String::from("Alice"),
        age: 25,
    };

    // Debug
    println!("p1: {:?}", p1);
    println!("p1: {:#?}", p1);  // 美化格式

    // Clone
    let p2 = p1.clone();

    // PartialEq
    let p3 = Person {
        name: String::from("Alice"),
        age: 25,
    };

    println!("p1 == p2: {}", p1 == p2);
    println!("p1 == p3: {}", p1 == p3);  // false(String 内容相等但不是同一实例)
}
▶ Run

手动实现 Debug

rust
struct Point {
    x: f64,
    y: f64,
}

// 手动实现 Debug
impl std::fmt::Debug for Point {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "Point({}, {})", self.x, self.y)
    }
}

fn main() {
    let p = Point { x: 1.0, y: 2.0 };
    println!("{:?}", p);  // Point(1.0, 2.0)
}
▶ Run

完整示例

示例 1:学生管理系统

rust
#[derive(Debug)]
struct Student {
    id: u32,
    name: String,
    grades: Vec<f64>,
}

impl Student {
    fn new(id: u32, name: String) -> Self {
        Self {
            id,
            name,
            grades: Vec::new(),
        }
    }

    fn add_grade(&mut self, grade: f64) {
        self.grades.push(grade);
    }

    fn average(&self) -> f64 {
        if self.grades.is_empty() {
            return 0.0;
        }
        let sum: f64 = self.grades.iter().sum();
        sum / self.grades.len() as f64
    }

    fn print_report(&self) {
        println!("╔════════════════════════════════════╗");
        println!("║          学生成绩单                ║");
        println!("╠════════════════════════════════════╣");
        println!("║ ID: {:<4} │ 姓名:{:<10}        ║", self.id, self.name);
        println!("╠════════════════════════════════════╣");
        print!("║ 成绩:");
        for grade in &self.grades {
            print!("{:.0} ", grade);
        }
        println!("║");
        println!("╠════════════════════════════════════╣");
        println!("║ 平均分:{:<22.2} ║", self.average());
        println!("╚════════════════════════════════════╝");
    }
}

fn main() {
    let mut student = Student::new(1, String::from("张三"));

    student.add_grade(90.0);
    student.add_grade(85.0);
    student.add_grade(95.0);
    student.add_grade(88.0);

    student.print_report();
}
▶ Run

示例 2:几何图形系统

rust
#[derive(Debug, Clone, Copy)]
struct Point {
    x: f64,
    y: f64,
}

#[derive(Debug, Clone)]
struct Rectangle {
    top_left: Point,
    bottom_right: Point,
}

impl Point {
    fn new(x: f64, y: f64) -> Self {
        Self { x, y }
    }

    fn distance_from_origin(&self) -> f64 {
        (self.x.powi(2) + self.y.powi(2)).sqrt()
    }
}

impl Rectangle {
    fn new(x1: f64, y1: f64, x2: f64, y2: f64) -> Self {
        Self {
            top_left: Point::new(x1, y1.max(y2)),
            bottom_right: Point::new(x2, y1.min(y2)),
        }
    }

    fn width(&self) -> f64 {
        (self.bottom_right.x - self.top_left.x).abs()
    }

    fn height(&self) -> f64 {
        (self.top_left.y - self.bottom_right.y).abs()
    }

    fn area(&self) -> f64 {
        self.width() * self.height()
    }

    fn contains(&self, point: &Point) -> bool {
        point.x >= self.top_left.x
            && point.x <= self.bottom_right.x
            && point.y <= self.top_left.y
            && point.y >= self.bottom_right.y
    }

    fn translate(&mut self, dx: f64, dy: f64) {
        self.top_left.x += dx;
        self.top_left.y += dy;
        self.bottom_right.x += dx;
        self.bottom_right.y += dy;
    }
}

fn main() {
    let mut rect = Rectangle::new(0.0, 10.0, 20.0, 0.0);

    println!("矩形:{:?}", rect);
    println!("宽度:{}", rect.width());
    println!("高度:{}", rect.height());
    println!("面积:{}", rect.area());

    let p1 = Point::new(5.0, 5.0);
    let p2 = Point::new(25.0, 5.0);

    println!("p1 在矩形内:{}", rect.contains(&p1));
    println!("p2 在矩形内:{}", rect.contains(&p2));

    rect.translate(10.0, 10.0);
    println!("平移后:{:?}", rect);
}
▶ Run

常见错误

错误 1:忘记 mut

rust
struct Counter {
    count: u32,
}

fn main() {
    let counter = Counter { count: 0 };
    // counter.count += 1;  // ❌ 错误:需要 mut

    let mut counter = Counter { count: 0 };
    counter.count += 1;  // ✅ 正确
}
▶ Run

错误信息:

error[E0594]: cannot assign to `counter.count`, which is not mutable
 --> src/main.rs:7:5
  |
7 |     counter.count += 1;
  |     ^^^^^^^^^^^^^ cannot assign

错误 2:字段类型不匹配

rust
struct Person {
    name: String,
    age: u32,
}

fn main() {
    // let p = Person {
    //     name: "Alice",  // ❌ 错误:需要 String,不是&str
    //     age: 25,
    // };

    let p = Person {
        name: String::from("Alice"),
        age: 25,
    };
}
▶ Run

错误 3:字段不完整

rust
struct Point {
    x: i32,
    y: i32,
}

fn main() {
    // let p = Point { x: 1 };  // ❌ 错误:缺少 y 字段

    let p = Point { x: 1, y: 2 };
}
▶ Run

错误信息:

error[E0063]: missing field `y` in initializer of `Point`
 --> src/main.rs:7:13
  |
7 |     let p = Point { x: 1 };
  |             ^^^^^ missing `y`

错误 4:所有权问题

rust
struct User {
    name: String,
}

fn main() {
    let user1 = User {
        name: String::from("alice"),
    };

    let user2 = User {
        ..user1  // user1.name 被移动
    };

    // println!("{}", user1.name);  // ❌ 错误:已被移动
}
▶ Run

调试技巧

打印结构体

rust
#[derive(Debug)]
struct Person {
    name: String,
    age: u32,
}

fn main() {
    let p = Person {
        name: String::from("Alice"),
        age: 25,
    };

    // 基本调试输出
    println!("{:?}", p);

    // 美化格式
    println!("{:#?}", p);

    // 使用 dbg!
    dbg!(&p);
}
▶ Run

自定义 Debug 输出

rust
struct Password(String);

impl std::fmt::Debug for Password {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        // 不显示实际密码
        write!(f, "Password(****)")
    }
}

fn main() {
    let pwd = Password(String::from("secret123"));
    println!("{:?}", pwd);  // Password(****)
}
▶ Run

练习

练习 1:图书管理

创建 Book 结构体,包含:

  • 书名(title)
  • 作者(author)
  • 出版年份(year)

实现方法:

  • is_new(&self) -> bool - 判断是否是近 5 年出版

练习 2:圆形计算

创建 Circle 结构体,包含:

  • 圆心(center: Point)
  • 半径(radius: f64)

实现方法:

  • area(&self) -> f64 - 计算面积
  • circumference(&self) -> f64 - 计算周长
  • contains(&self, point: &Point) -> bool - 判断点是否在圆内

练习 3:购物车

创建 CartItem 和 ShoppingCart 结构体,实现:

  • 添加商品
  • 移除商品
  • 计算总价

小结

结构体要点

概念说明
命名字段struct Person { name: String }
元组字段struct Color(i32, i32, i32)
单元结构体struct Marker;
方法fn method(&self)
关联函数fn new() -> Self
派生 Trait#[derive(Debug, Clone)]

self 的三种形式

形式用途示例
&self只读访问fn area(&self)
&mut self修改数据fn push(&mut self)
self消耗实例fn into_inner(self)

最佳实践

  1. 使用有意义的字段名,提高代码可读性
  2. 实现 new 构造函数,方便创建实例
  3. 派生常用 Trait(Debug, Clone, PartialEq)
  4. 区分&self 和&mut self,遵循借用规则
  5. 使用单元结构体作为标记类型

练习题

详见:练习题