Rust:Generics、Traitstor

一、泛型(Generics)

基本概念

泛型允许我们编写可复用的代码,这些代码可以处理多种类型而不需要为每种类型重写逻辑。通过泛型,我们可以创建类型参数化的函数、结构体、枚举和方法。

核心价值

  1. 代码复用:避免为不同类型重复编写相同逻辑
  2. 类型安全:编译时类型检查
  3. 零运行时开销:编译时生成具体类型代码

基本用法

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)); // 10
println!("较大的浮点数: {}", largest(3.14, 2.71)); // 3.14
println!("较大的字符: {}", largest('a', 'z')); // '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;

// 只接受实现了Display特质的类型
fn print_twice<T: Display>(value: T) {
println!("第一次: {}", value);
println!("第二次: {}", value);
}

// 使用where子句更清晰
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. 抽象行为定义:定义类型必须实现的方法
  2. 多态支持:通过特质对象实现运行时多态
  3. 代码组织:将相关功能分组

基本用法

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
}

// 使用默认的summarize实现
}

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
// 使用impl Trait语法
fn notify(item: &impl Summary) {
println!("新通知! {}", item.summarize());
}

// 使用trait bound语法
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 {} // 自动获得log实现

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); // Point { x: 4, y: 6 }
}

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()); // "Hello World"
}

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. 避免过度泛化:只在真正需要时使用泛型
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)
主要目的 代码复用,类型参数化 定义共享行为,实现多态
实现方式 编译时单态化 静态分发或动态分发
性能 零运行时开销 静态分发零开销,动态分发有开销
使用场景 创建通用数据结构/算法 定义接口,实现多态行为
约束 通过特质约束类型能力 本身就是行为约束
灵活性 编译时确定具体类型 运行时可通过特质对象处理多种类型

Rust:Generics、Traitstor
http://blog.luliang.online/2025/09/27/Rust(四)/
作者
Luyoung
发布于
2025年9月27日
许可协议