一、泛型(Generics)
基本概念
泛型允许我们编写可复用的代码,这些代码可以处理多种类型而不需要为每种类型重写逻辑。通过泛型,我们可以创建类型参数化的函数、结构体、枚举和方法。
核心价值
- 代码复用:避免为不同类型重复编写相同逻辑
- 类型安全:编译时类型检查
- 零运行时开销:编译时生成具体类型代码
基本用法
1. 泛型函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| fn largest<T: PartialOrd>(a: T, b: T) -> T { if a > b { a } else { b } }
fn main() { println!("较大的整数: {}", largest(5, 10)); println!("较大的浮点数: {}", largest(3.14, 2.71)); println!("较大的字符: {}", largest('a', 'z')); }
|
2. 泛型结构体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| struct Point<T> { x: T, y: T, }
impl<T> Point<T> { fn new(x: T, y: T) -> Self { Point { x, y } } }
fn main() { let integer_point = Point::new(5, 10); let float_point = Point::new(1.0, 4.0); let string_point = Point::new("left", "right"); }
|
3. 泛型枚举
1 2 3 4 5 6 7 8 9 10 11 12
| enum Result<T, E> { Ok(T), Err(E), }
fn divide(a: f64, b: f64) -> Result<f64, String> { if b == 0.0 { Result::Err("Division by zero".to_string()) } else { Result::Ok(a / b) } }
|
泛型约束
使用特质来限制泛型类型的能力:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| use std::fmt::Display;
fn print_twice<T: Display>(value: T) { println!("第一次: {}", value); println!("第二次: {}", value); }
fn compare_and_print<T, U>(a: T, b: U) where T: Display + PartialOrd, U: Display + Into<T>, { let b_converted: T = b.into(); if a > b_converted { println!("{} 大于 {}", a, b); } else { println!("{} 不大于 {}", a, b); } }
|
二、特质(Traits)
基本概念
特质定义了类型可以实现的共享行为。它们类似于其他语言中的接口(interface),但更强大。
核心价值
- 抽象行为定义:定义类型必须实现的方法
- 多态支持:通过特质对象实现运行时多态
- 代码组织:将相关功能分组
基本用法
1. 定义和实现特质
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| trait Summary { fn summarize(&self) -> String { String::from("(阅读更多...)") }
fn title(&self) -> &str; }
struct NewsArticle { title: String, content: String, }
impl Summary for NewsArticle { fn title(&self) -> &str { &self.title }
}
struct Tweet { username: String, message: String, }
impl Summary for Tweet { fn title(&self) -> &str { &self.username }
fn summarize(&self) -> String { format!("{}: {}", self.username, self.message) } }
|
2. 特质作为参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| fn notify(item: &impl Summary) { println!("新通知! {}", item.summarize()); }
fn notify_multi<T: Summary>(item1: &T, item2: &T) { println!("通知1: {}", item1.summarize()); println!("通知2: {}", item2.summarize()); }
fn display_and_notify(item: &(impl Summary + Display)) { println!("显示: {}", item); println!("摘要: {}", item.summarize()); }
|
3. 特质作为返回值
1 2 3 4 5 6 7 8 9 10 11 12 13
| fn create_summarizable(is_tweet: bool) -> impl Summary { if is_tweet { Tweet { username: "rustacean".to_string(), message: "Learning Rust traits!".to_string(), } } else { NewsArticle { title: "Rust in Depth".to_string(), content: "Detailed guide to Rust features".to_string(), } } }
|
高级用法
1. 特质继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| trait Printable { fn format(&self) -> String; }
trait Loggable: Printable { fn log(&self) { println!("日志: {}", self.format()); } }
struct Data { value: i32, }
impl Printable for Data { fn format(&self) -> String { format!("值: {}", self.value) } }
impl Loggable for Data {}
|
2. 关联类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| trait Iterator { type Item;
fn next(&mut self) -> Option<Self::Item>; }
struct Counter { count: u32, }
impl Iterator for Counter { type Item = u32;
fn next(&mut self) -> Option<Self::Item> { if self.count < 5 { self.count += 1; Some(self.count) } else { None } } }
|
3. 泛型特质
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| trait Converter<T> { fn convert(&self) -> T; }
struct StringToInt(String);
impl Converter<i32> for StringToInt { fn convert(&self) -> i32 { self.0.parse().unwrap_or(0) } }
struct IntToString(i32);
impl Converter<String> for IntToString { fn convert(&self) -> String { self.0.to_string() } }
|
三、常见用法与模式
1. 运算符重载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| use std::ops::Add;
#[derive(Debug, Clone, Copy)] struct Point { x: i32, y: i32, }
impl Add for Point { type Output = Point;
fn add(self, other: Point) -> Point { Point { x: self.x + other.x, y: self.y + other.y, } } }
fn main() { let p1 = Point { x: 1, y: 2 }; let p2 = Point { x: 3, y: 4 }; let p3 = p1 + p2; println!("{:?}", p3); }
|
2. 静态分发 vs 动态分发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| fn process_static<T: Summary>(item: &T) { println!("{}", item.summarize()); }
fn process_dynamic(item: &dyn Summary) { println!("{}", item.summarize()); }
fn main() { let article = NewsArticle { }; let tweet = Tweet { };
process_static(&article); process_static(&tweet);
let items: Vec<&dyn Summary> = vec![&article, &tweet]; for item in items { process_dynamic(item); } }
|
3. 扩展方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| trait StringExt { fn to_title_case(&self) -> String; }
impl StringExt for str { fn to_title_case(&self) -> String { self.split_whitespace() .map(|word| { let mut chars = word.chars(); match chars.next() { None => String::new(), Some(first) => first.to_uppercase().chain(chars).collect(), } }) .collect::<Vec<String>>() .join(" ") } }
fn main() { let s = "hello world"; println!("{}", s.to_title_case()); }
|
4. 条件方法实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| struct Pair<T> { x: T, y: T, }
impl<T> Pair<T> { fn new(x: T, y: T) -> Self { Self { x, y } } }
impl<T: Display + PartialOrd> Pair<T> { fn display_comparison(&self) { if self.x > self.y { println!("x 大于 y"); } else if self.x < self.y { println!("x 小于 y"); } else { println!("x 等于 y"); } } }
|
四、实际应用场景
1. 通用数据结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| struct Stack<T> { items: Vec<T>, }
impl<T> Stack<T> { fn new() -> Self { Stack { items: Vec::new() } }
fn push(&mut self, item: T) { self.items.push(item); }
fn pop(&mut self) -> Option<T> { self.items.pop() }
fn peek(&self) -> Option<&T> { self.items.last() } }
|
2. 错误处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| use std::error::Error; use std::fmt;
#[derive(Debug)] struct CustomError { message: String, }
impl Error for CustomError {}
impl fmt::Display for CustomError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "自定义错误: {}", self.message) } }
fn might_fail(flag: bool) -> Result<(), CustomError> { if flag { Ok(()) } else { Err(CustomError { message: "操作失败".to_string(), }) } }
|
3. 策略模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| trait CompressionStrategy { fn compress(&self, data: &[u8]) -> Vec<u8>; }
struct ZipCompression; impl CompressionStrategy for ZipCompression { fn compress(&self, data: &[u8]) -> Vec<u8> { data.iter().map(|b| b.wrapping_sub(1)).collect() } }
struct GzipCompression; impl CompressionStrategy for GzipCompression { fn compress(&self, data: &[u8]) -> Vec<u8> { data.iter().map(|b| b.wrapping_add(1)).collect() } }
struct Compressor { strategy: Box<dyn CompressionStrategy>, }
impl Compressor { fn new(strategy: Box<dyn CompressionStrategy>) -> Self { Compressor { strategy } }
fn compress_data(&self, data: &[u8]) -> Vec<u8> { self.strategy.compress(data) } }
|
五、最佳实践
- 优先使用泛型:当类型在编译时已知时
- 合理使用特质对象:当需要处理多种类型时
- 保持特质小而专注:单一职责原则
- 使用泛型约束:明确类型要求
- 利用默认实现:减少重复代码
- 避免过度泛化:只在真正需要时使用泛型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| fn process_data<T>(data: T) where T: Display + Debug + Serialize, { }
fn overly_generic<T, U, V>(a: T, b: U, c: V) where T: Display, U: Debug, V: Clone, { }
|
六、总结对比
特性 |
泛型(Generics) |
特质(Traits) |
主要目的 |
代码复用,类型参数化 |
定义共享行为,实现多态 |
实现方式 |
编译时单态化 |
静态分发或动态分发 |
性能 |
零运行时开销 |
静态分发零开销,动态分发有开销 |
使用场景 |
创建通用数据结构/算法 |
定义接口,实现多态行为 |
约束 |
通过特质约束类型能力 |
本身就是行为约束 |
灵活性 |
编译时确定具体类型 |
运行时可通过特质对象处理多种类型 |