Skip to content

Trait 实战总结

> 综合运用 Trait 知识,通过实战示例巩固 Trait 定义、实现和使用的核心技能。

完整示例

示例 1:可绘制形状系统

rust
use std::fmt::Display;

/// 可绘制的形状
trait Draw {
    fn draw(&self) -> String;
    fn area(&self) -> f64;
}

/// 圆形
#[derive(Debug, Clone)]
struct Circle {
    radius: f64,
}

impl Draw for Circle {
    fn draw(&self) -> String {
        format!("○ 圆形 (半径 = {})", self.radius)
    }

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

/// 矩形
#[derive(Debug, Clone)]
struct Rectangle {
    width: f64,
    height: f64,
}

impl Draw for Rectangle {
    fn draw(&self) -> String {
        format!("□ 矩形 ({}x{})", self.width, self.height)
    }

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

/// 三角形
#[derive(Debug, Clone)]
struct Triangle {
    base: f64,
    height: f64,
}

impl Draw for Triangle {
    fn draw(&self) -> String {
        format!("△ 三角形 (底 = {}, 高 = {})", self.base, self.height)
    }

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

/// 画布
struct Canvas {
    shapes: Vec<Box<dyn Draw>>,
}

impl Canvas {
    fn new() -> Self {
        Canvas {
            shapes: Vec::new(),
        }
    }

    fn add(&mut self, shape: impl Draw + 'static) {
        self.shapes.push(Box::new(shape));
    }

    fn render(&self) {
        println!("╔════════════════════════════════════╗");
        println!("║           画布内容                  ║");
        println!("╠════════════════════════════════════╣");
        for (i, shape) in self.shapes.iter().enumerate() {
            println!("║ {}: {:<28} ║", i + 1, shape.draw());
        }
        println!("╠════════════════════════════════════╣");
        println!("║ 总面积:{:<26.2f} ║", self.total_area());
        println!("╚════════════════════════════════════╝");
    }

    fn total_area(&self) -> f64 {
        self.shapes.iter().map(|s| s.area()).sum()
    }
}

fn main() {
    let mut canvas = Canvas::new();

    canvas.add(Circle { radius: 5.0 });
    canvas.add(Rectangle { width: 10.0, height: 20.0 });
    canvas.add(Triangle { base: 6.0, height: 8.0 });
    canvas.add(Circle { radius: 3.0 });

    canvas.render();
}
▶ Run

输出:

╔════════════════════════════════════╗
║           画布内容                  ║
╠════════════════════════════════════╣
║ 1: ○ 圆形 (半径 = 5)            ║
║ 2: □ 矩形 (10x20)               ║
║ 3: △ 三角形 (底 = 6, 高 = 8)    ║
║ 4: ○ 圆形 (半径 = 3)            ║
╠════════════════════════════════════╣
║ 总面积:310.54                    ║
╚════════════════════════════════════╝

示例 2:插件系统

rust
/// 插件 Trait
trait Plugin {
    fn name(&self) -> &str;
    fn version(&self) -> &str;
    fn execute(&self, input: &str) -> String;
}

/// 大写插件
struct UppercasePlugin;

impl Plugin for UppercasePlugin {
    fn name(&self) -> &str {
        "Uppercase"
    }

    fn version(&self) -> &str {
        "1.0.0"
    }

    fn execute(&self, input: &str) -> String {
        input.to_uppercase()
    }
}

/// 反转插件
struct ReversePlugin;

impl Plugin for ReversePlugin {
    fn name(&self) -> &str {
        "Reverse"
    }

    fn version(&self) -> &str {
        "1.0.0"
    }

    fn execute(&self, input: &str) -> String {
        input.chars().rev().collect()
    }
}

/// 去空格插件
struct TrimPlugin;

impl Plugin for TrimPlugin {
    fn name(&self) -> &str {
        "Trim"
    }

    fn version(&self) -> &str {
        "1.0.0"
    }

    fn execute(&self, input: &str) -> String {
        input.trim().to_string()
    }
}

/// 插件管理器
struct PluginManager {
    plugins: Vec<Box<dyn Plugin>>,
}

impl PluginManager {
    fn new() -> Self {
        PluginManager {
            plugins: Vec::new(),
        }
    }

    fn register(&mut self, plugin: impl Plugin + 'static) {
        println!("注册插件:{} v{}", plugin.name(), plugin.version());
        self.plugins.push(Box::new(plugin));
    }

    fn process(&self, input: &str) -> String {
        let mut result = input.to_string();
        for plugin in &self.plugins {
            result = plugin.execute(&result);
        }
        result
    }

    fn list_plugins(&self) {
        println!("已注册的插件:");
        for plugin in &self.plugins {
            println!("  - {} v{}", plugin.name(), plugin.version());
        }
    }
}

fn main() {
    let mut manager = PluginManager::new();

    manager.register(TrimPlugin);
    manager.register(UppercasePlugin);
    manager.register(ReversePlugin);

    manager.list_plugins();

    let input = "  hello world  ";
    println!("\n输入:'{}'", input);
    println!("输出:'{}'", manager.process(input));
}
▶ Run

常见错误

错误 1:缺少必要的方法实现

rust
trait Summary {
    fn summarize(&self) -> String;
}

struct Tweet {
    content: String,
}

// ❌ 错误:缺少 summarize 实现
// impl Summary for Tweet {}

// ✅ 正确
impl Summary for Tweet {
    fn summarize(&self) -> String {
        self.content.clone()
    }
}
▶ Run

错误信息:

error[E0046]: not all trait items implemented, missing: `summarize`

错误 2:方法签名不匹配

rust
trait Summary {
    fn summarize(&self) -> String;
}

struct Tweet {
    content: String,
}

// ❌ 错误:签名不匹配
// impl Summary for Tweet {
//     fn summarize(&self) { }  // 缺少返回类型
// }

// ✅ 正确
impl Summary for Tweet {
    fn summarize(&self) -> String {
        self.content.clone()
    }
}
▶ Run

错误 3:Sized 问题

rust
// ❌ 错误:dyn Trait 大小不固定
// fn process(item: dyn Summary) { }

// ✅ 正确:使用引用或 Box
fn process(item: &dyn Summary) { }
fn process_box(item: Box<dyn Summary>) { }
▶ Run

练习

练习 1:Area Trait

定义一个 Area trait,为不同形状计算面积:

  • Circle(圆)
  • Rectangle(矩形)
  • Triangle(三角形)

练习 2:Serialize Trait

实现一个 Serialize trait:

rust
trait Serialize {
    fn to_json(&self) -> String;
}
▶ Run

为 User 结构体实现该 trait。

练习 3:Compare Trait

创建 Compare trait,实现:

  • max(a, b) - 返回较大值
  • min(a, b) - 返回较小值

小结

Trait 核心概念

概念说明
定义trait Name { fn method(); }
实现impl Trait for Type
默认实现提供方法的默认行为
泛型约束T: Traitimpl Trait
Trait 对象Box<dyn Trait>(动态分发)

常用模式

rust
// 1. 作为参数
fn process(item: &impl Trait) { }
fn process<T: Trait>(item: &T) { }

// 2. 作为返回值
fn create() -> impl Trait { }
fn create() -> Box<dyn Trait> { }

// 3. 多个约束
fn process<T: Trait1 + Trait2>(item: &T) { }

// 4. where 子句
fn process<T>(item: &T) where T: Trait1 + Trait2 { }
▶ Run

关键要点

  1. Trait 定义行为,结构体/枚举实现行为
  2. 孤儿规则限制为外部类型实现外部 Trait
  3. 默认实现可以减少重复代码
  4. impl Trait 用于静态分发(高效)
  5. dyn Trait 用于动态分发(灵活)

小结

本章我们学习了:

  • Trait 的定义、实现和默认实现
  • impl Trait 和 dyn Trait 的区别和用法
  • Trait 作为参数和返回值
  • Trait 对象的对象安全规则
  • 实战案例:可绘制形状系统和插件系统

练习题

详见:练习题