Rust 系统编程语言完全教程 / 第11章:Trait 系统
第11章:Trait 系统
11.1 什么是 Trait
Trait 定义了类型必须实现的行为(方法签名),类似其他语言的接口(interface)。
定义与实现
// 定义 trait
trait Drawable {
fn draw(&self);
fn area(&self) -> f64;
}
struct Circle {
radius: f64,
}
struct Square {
side: f64,
}
// 为 Circle 实现 trait
impl Drawable for Circle {
fn draw(&self) {
println!("画一个半径为 {} 的圆", self.radius);
}
fn area(&self) -> f64 {
std::f64::consts::PI * self.radius * self.radius
}
}
// 为 Square 实现 trait
impl Drawable for Square {
fn draw(&self) {
println!("画一个边长为 {} 的正方形", self.side);
}
fn area(&self) -> f64 {
self.side * self.side
}
}
fn main() {
let shapes: Vec<Box<dyn Drawable>> = vec![
Box::new(Circle { radius: 5.0 }),
Box::new(Square { side: 4.0 }),
];
for shape in &shapes {
shape.draw();
println!("面积: {:.2}\n", shape.area());
}
}
11.2 默认实现
trait Greeting {
fn name(&self) -> &str;
// 默认实现(可被覆盖)
fn hello(&self) -> String {
format!("你好,我是 {}", self.name())
}
fn goodbye(&self) -> String {
format!("{} 说再见", self.name())
}
}
struct Person {
name: String,
}
impl Greeting for Person {
fn name(&self) -> &str {
&self.name
}
// hello 和 goodbye 使用默认实现
}
struct Robot {
id: u32,
}
impl Greeting for Robot {
fn name(&self) -> &str {
"机器人"
}
// 覆盖默认实现
fn hello(&self) -> String {
format!("[系统{}] 初始化完毕", self.id)
}
}
fn main() {
let person = Person { name: "张三".to_string() };
let robot = Robot { id: 42 };
println!("{}", person.hello()); // 你好,我是 张三
println!("{}", person.goodbye()); // 张三 说再见
println!("{}", robot.hello()); // [系统42] 初始化完毕
println!("{}", robot.goodbye()); // 机器人 说再见
}
11.3 Trait 作为参数
impl Trait 语法
trait Summary {
fn summarize(&self) -> String;
}
struct Article {
title: String,
content: String,
}
impl Summary for Article {
fn summarize(&self) -> String {
format!("{}: {}", self.title, &self.content[..50.min(self.content.len())])
}
}
struct Tweet {
username: String,
text: String,
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("@{}: {}", self.username, self.text)
}
}
// impl Trait 语法(语法糖)
fn notify(item: &impl Summary) {
println!("新消息: {}", item.summarize());
}
// Trait bound 语法(等价写法)
fn notify_bound<T: Summary>(item: &T) {
println!("新消息: {}", item.summarize());
}
fn main() {
let article = Article {
title: "Rust 发布新版本".to_string(),
content: "Rust 2024 edition 带来了许多新特性...".to_string(),
};
let tweet = Tweet {
username: "rustlang".to_string(),
text: "Rust is awesome!".to_string(),
};
notify(&article);
notify(&tweet);
}
多个 Trait 约束
use std::fmt::{Debug, Display};
trait Summary {
fn summarize(&self) -> String;
}
fn display_and_summary<T: Display + Summary>(item: &T) {
println!("Display: {}", item);
println!("Summary: {}", item.summarize());
}
// where 子句(更清晰)
fn complex_function<T, U>(t: &T, u: &U) -> String
where
T: Display + Clone,
U: Debug + Summary,
{
format!("t={}, u={:?}", t, u)
}
11.4 Trait 作为返回类型
trait Summary {
fn summarize(&self) -> String;
}
struct Article {
title: String,
}
impl Summary for Article {
fn summarize(&self) -> String {
format!("文章: {}", self.title)
}
}
struct Tweet {
text: String,
}
impl Summary for Tweet {
fn summarize(&self) -> String {
format!("推文: {}", self.text)
}
}
// 返回 impl Trait(静态分发,编译时确定具体类型)
fn create_summary(kind: &str) -> impl Summary {
Article {
title: format!("关于{}的文章", kind),
}
}
// 如果需要根据条件返回不同类型,需要 Box<dyn Trait>
fn create_summary_dynamic(kind: &str) -> Box<dyn Summary> {
if kind == "article" {
Box::new(Article { title: "文章标题".to_string() })
} else {
Box::new(Tweet { text: "推文内容".to_string() })
}
}
fn main() {
let s1 = create_summary("Rust");
println!("{}", s1.summarize());
let s2 = create_summary_dynamic("article");
let s3 = create_summary_dynamic("tweet");
println!("{}", s2.summarize());
println!("{}", s3.summarize());
}
11.5 静态分发与动态分发
| 特性 | 静态分发 (impl Trait / 泛型) | 动态分发 (dyn Trait) |
|---|
| 确定时间 | 编译时 | 运行时 |
| 性能 | 零开销(单态化) | 间接调用(vtable) |
| 二进制大小 | 较大(代码膨胀) | 较小 |
| 异构集合 | ❌ 不支持 | ✅ 支持 |
| 内联优化 | ✅ 可以 | ❌ 不能 |
trait Animal {
fn sound(&self) -> &str;
}
struct Dog;
struct Cat;
impl Animal for Dog {
fn sound(&self) -> &str { "汪汪" }
}
impl Animal for Cat {
fn sound(&self) -> &str { "喵喵" }
}
// 静态分发:编译器为每种类型生成专用版本
fn print_sound_static(animal: &impl Animal) {
println!("静态: {}", animal.sound());
}
// 动态分发:通过 vtable 进行间接调用
fn print_sound_dynamic(animal: &dyn Animal) {
println!("动态: {}", animal.sound());
}
fn main() {
let dog = Dog;
let cat = Cat;
// 静态分发
print_sound_static(&dog);
print_sound_static(&cat);
// 动态分发
print_sound_dynamic(&dog);
print_sound_dynamic(&cat);
// 异构集合需要动态分发
let animals: Vec<Box<dyn Animal>> = vec![
Box::new(Dog),
Box::new(Cat),
];
for animal in &animals {
println!("{}", animal.sound());
}
}
11.6 常用标准库 Trait
| Trait | 说明 | 派生 |
|---|
Debug | 调试格式化 {:?} | #[derive(Debug)] |
Display | 用户友好格式化 {} | 手动实现 |
Clone | 深拷贝 .clone() | #[derive(Clone)] |
Copy | 位拷贝(栈上类型) | #[derive(Copy, Clone)] |
PartialEq | 相等比较 == | #[derive(PartialEq)] |
Eq | 完全相等(浮点不可用) | #[derive(Eq, PartialEq)] |
PartialOrd | 部分排序 <, > | #[derive(PartialOrd)] |
Ord | 完全排序 .sort() | #[derive(Ord, PartialOrd)] |
Hash | 哈希计算 | #[derive(Hash)] |
Default | 默认值 | #[derive(Default)] |
From/Into | 类型转换 | 手动实现 From |
Iterator | 迭代器 | 手动实现 |
Display 实现
use std::fmt;
struct Color {
r: u8,
g: u8,
b: u8,
}
impl fmt::Display for Color {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "#{:02X}{:02X}{:02X}", self.r, self.g, self.b)
}
}
impl fmt::Debug for Color {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Color({}, {}, {})", self.r, self.g, self.b)
}
}
fn main() {
let red = Color { r: 255, g: 0, b: 0 };
println!("Display: {}", red); // #FF0000
println!("Debug: {:?}", red); // Color(255, 0, 0)
}
From/Into 转换
#[derive(Debug)]
struct Celsius(f64);
#[derive(Debug)]
struct Fahrenheit(f64);
impl From<Celsius> for Fahrenheit {
fn from(c: Celsius) -> Self {
Fahrenheit(c.0 * 9.0 / 5.0 + 32.0)
}
}
impl From<Fahrenheit> for Celsius {
fn from(f: Fahrenheit) -> Self {
Celsius((f.0 - 32.0) * 5.0 / 9.0)
}
}
fn main() {
let boiling = Celsius(100.0);
let f: Fahrenheit = boiling.into();
println!("{:?} = {:?}", Celsius(100.0), f);
let body = Fahrenheit(98.6);
let c: Celsius = body.into();
println!("{:?} = {:?}", Fahrenheit(98.6), c);
}
11.7 Trait 继承
trait Base {
fn base_method(&self);
}
trait Extended: Base {
fn extended_method(&self);
}
struct MyType;
impl Base for MyType {
fn base_method(&self) {
println!("基础方法");
}
}
impl Extended for MyType {
fn extended_method(&self) {
println!("扩展方法");
self.base_method(); // 可以调用父 trait 的方法
}
}
fn main() {
let obj = MyType;
obj.extended_method();
}
11.8 业务场景示例
序列化框架
trait Serializable {
fn serialize(&self) -> String;
fn content_type(&self) -> &str;
}
trait Deserializable: Sized {
fn deserialize(data: &str) -> Result<Self, String>;
}
#[derive(Debug)]
struct User {
name: String,
email: String,
age: u32,
}
impl Serializable for User {
fn serialize(&self) -> String {
format!("name={},email={},age={}", self.name, self.email, self.age)
}
fn content_type(&self) -> &str {
"text/plain"
}
}
impl Deserializable for User {
fn deserialize(data: &str) -> Result<Self, String> {
let mut name = String::new();
let mut email = String::new();
let mut age = 0;
for pair in data.split(',') {
let parts: Vec<&str> = pair.splitn(2, '=').collect();
match parts[0] {
"name" => name = parts[1].to_string(),
"email" => email = parts[1].to_string(),
"age" => age = parts[1].parse().map_err(|e| format!("{}", e))?,
_ => {}
}
}
Ok(User { name, email, age })
}
}
fn transfer<T: Serializable>(item: &T) -> String {
println!("Content-Type: {}", item.content_type());
item.serialize()
}
fn main() {
let user = User {
name: "Alice".to_string(),
email: "alice@example.com".to_string(),
age: 30,
};
let data = transfer(&user);
println!("序列化: {}", data);
let user2 = User::deserialize(&data).unwrap();
println!("反序列化: {:?}", user2);
}
插件系统
trait Plugin {
fn name(&self) -> &str;
fn version(&self) -> &str;
fn execute(&self, input: &str) -> String;
}
struct UpperCasePlugin;
struct ReversePlugin;
struct CountPlugin;
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() }
}
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() }
}
impl Plugin for CountPlugin {
fn name(&self) -> &str { "Count" }
fn version(&self) -> &str { "1.0.0" }
fn execute(&self, input: &str) -> String {
format!("{} ({}字符)", input, input.chars().count())
}
}
struct PluginManager {
plugins: Vec<Box<dyn Plugin>>,
}
impl PluginManager {
fn new() -> Self {
Self { plugins: Vec::new() }
}
fn register(&mut self, plugin: Box<dyn Plugin>) {
println!("注册插件: {} v{}", plugin.name(), plugin.version());
self.plugins.push(plugin);
}
fn process(&self, input: &str) -> String {
let mut result = input.to_string();
for plugin in &self.plugins {
result = plugin.execute(&result);
}
result
}
}
fn main() {
let mut manager = PluginManager::new();
manager.register(Box::new(UpperCasePlugin));
manager.register(Box::new(ReversePlugin));
manager.register(Box::new(CountPlugin));
let result = manager.process("hello world");
println!("最终结果: {}", result);
}
11.9 本章小结
| 要点 | 说明 |
|---|
| Trait 定义 | 定义类型必须实现的行为 |
| 默认实现 | trait 方法可以提供默认实现 |
| impl Trait | 语法糖,用于参数和返回值 |
| Trait bound | T: Trait 形式的泛型约束 |
| 静态分发 | 编译时确定,零开销 |
| 动态分发 | 运行时通过 vtable 调用 |
| 常用 Trait | Debug、Display、Clone、Copy、From 等 |
扩展阅读
- Rust Book - Trait — 官方教程
- Rust Reference - Traits — 语言参考
- dyn Trait vs impl Trait — trait 对象详解