Trait 实战总结
> 综合运用 Trait 知识,通过实战示例巩固 Trait 定义、实现和使用的核心技能。
完整示例
示例 1:可绘制形状系统
rust
▶ Runuse 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();
}输出:
╔════════════════════════════════════╗
║ 画布内容 ║
╠════════════════════════════════════╣
║ 1: ○ 圆形 (半径 = 5) ║
║ 2: □ 矩形 (10x20) ║
║ 3: △ 三角形 (底 = 6, 高 = 8) ║
║ 4: ○ 圆形 (半径 = 3) ║
╠════════════════════════════════════╣
║ 总面积:310.54 ║
╚════════════════════════════════════╝示例 2:插件系统
rust
▶ Run/// 插件 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));
}常见错误
错误 1:缺少必要的方法实现
rust
▶ Runtrait 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()
}
}错误信息:
error[E0046]: not all trait items implemented, missing: `summarize`错误 2:方法签名不匹配
rust
▶ Runtrait 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()
}
}错误 3:Sized 问题
rust
▶ Run// ❌ 错误:dyn Trait 大小不固定
// fn process(item: dyn Summary) { }
// ✅ 正确:使用引用或 Box
fn process(item: &dyn Summary) { }
fn process_box(item: Box<dyn Summary>) { }练习
练习 1:Area Trait
定义一个 Area trait,为不同形状计算面积:
- Circle(圆)
- Rectangle(矩形)
- Triangle(三角形)
练习 2:Serialize Trait
实现一个 Serialize trait:
rust
▶ Runtrait Serialize {
fn to_json(&self) -> String;
}为 User 结构体实现该 trait。
练习 3:Compare Trait
创建 Compare trait,实现:
max(a, b)- 返回较大值min(a, b)- 返回较小值
小结
Trait 核心概念
| 概念 | 说明 |
|---|---|
| 定义 | trait Name { fn method(); } |
| 实现 | impl Trait for Type |
| 默认实现 | 提供方法的默认行为 |
| 泛型约束 | T: Trait 或 impl Trait |
| Trait 对象 | Box<dyn Trait>(动态分发) |
常用模式
rust
▶ Run// 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 { }关键要点
- Trait 定义行为,结构体/枚举实现行为
- 孤儿规则限制为外部类型实现外部 Trait
- 默认实现可以减少重复代码
- impl Trait 用于静态分发(高效)
- dyn Trait 用于动态分发(灵活)
小结
本章我们学习了:
- Trait 的定义、实现和默认实现
- impl Trait 和 dyn Trait 的区别和用法
- Trait 作为参数和返回值
- Trait 对象的对象安全规则
- 实战案例:可绘制形状系统和插件系统
练习题
详见:练习题