Rust 系统编程语言完全教程 / 第12章:泛型
第12章:泛型
12.1 为什么需要泛型
// 没有泛型:需要为每种类型写一个函数
fn largest_i32(list: &[i32]) -> &i32 {
let mut largest = &list[0];
for item in list {
if item > largest { largest = item; }
}
largest
}
fn largest_f64(list: &[f64]) -> &f64 {
let mut largest = &list[0];
for item in list {
if item > largest { largest = item; }
}
largest
}
// 使用泛型:一个函数适用于多种类型
fn largest<T: PartialOrd>(list: &[T]) -> &T {
let mut largest = &list[0];
for item in list {
if item > largest { largest = item; }
}
largest
}
fn main() {
let numbers = vec![34, 50, 25, 100, 65];
println!("最大数字: {}", largest(&numbers));
let chars = vec!['y', 'm', 'a', 'q'];
println!("最大字符: {}", largest(&chars));
let floats = vec![3.14, 2.71, 1.41, 1.73];
println!("最大浮点: {}", largest(&floats));
}
12.2 泛型函数
基本语法
fn first<T>(list: &[T]) -> Option<&T> {
list.first()
}
fn swap<T>(a: T, b: T) -> (T, T) {
(b, a)
}
fn pair<A, B>(a: A, b: B) -> (A, B) {
(a, b)
}
fn main() {
let nums = vec![1, 2, 3];
println!("first: {:?}", first(&nums));
let (x, y) = swap(1, 2);
println!("swap: {}, {}", x, y);
let p = pair("hello", 42);
println!("pair: {:?}", p);
}
多个泛型参数
use std::fmt::{Debug, Display};
fn print_pair<T: Display, U: Display>(first: T, second: U) {
println!("({}, {})", first, second);
}
fn debug_pair<T: Debug, U: Debug>(first: T, second: U) {
println!("({:?}, {:?})", first, second);
}
fn main() {
print_pair(42, "hello");
print_pair(3.14, true);
debug_pair(vec![1, 2], (3, 4));
}
12.3 泛型结构体
基本定义
#[derive(Debug)]
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn new(x: T, y: T) -> Self {
Self { x, y }
}
fn x(&self) -> &T {
&self.x
}
fn y(&self) -> &T {
&self.y
}
}
// 只为特定类型实现方法
impl Point<f64> {
fn distance_from_origin(&self) -> f64 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}
fn main() {
let integer_point = Point::new(5, 10);
let float_point = Point::new(1.0, 4.0);
println!("整数点: {:?}", integer_point);
println!("浮点点: {:?}", float_point);
println!("到原点距离: {}", float_point.distance_from_origin());
// integer_point.distance_from_origin(); // ❌ 只有 Point<f64> 有这个方法
}
多泛型参数
#[derive(Debug)]
struct Pair<T, U> {
first: T,
second: U,
}
impl<T, U> Pair<T, U> {
fn new(first: T, second: U) -> Self {
Self { first, second }
}
// 将 Pair<T, U> 转换为 Pair<T, T>
fn mixup<V, W>(self, other: Pair<V, W>) -> Pair<T, W> {
Pair {
first: self.first,
second: other.second,
}
}
}
fn main() {
let p1 = Pair::new(5, 10.4);
let p2 = Pair::new("Hello", 'c');
let p3 = p1.mixup(p2);
println!("混合: {:?}", p3); // Pair { first: 5, second: 'c' }
}
泛型枚举
// Option 和 Result 就是泛型枚举
// enum Option<T> { Some(T), None }
// enum Result<T, E> { Ok(T), Err(E) }
#[derive(Debug)]
enum Either<L, R> {
Left(L),
Right(R),
}
impl<L, R> Either<L, R> {
fn is_left(&self) -> bool {
matches!(self, Either::Left(_))
}
fn is_right(&self) -> bool {
matches!(self, Either::Right(_))
}
fn map_left<F, NewL>(self, f: F) -> Either<NewL, R>
where
F: FnOnce(L) -> NewL,
{
match self {
Either::Left(l) => Either::Left(f(l)),
Either::Right(r) => Either::Right(r),
}
}
}
fn main() {
let left: Either<i32, String> = Either::Left(42);
let right: Either<i32, String> = Either::Right("hello".to_string());
println!("left: {:?}, is_left={}", left, left.is_left());
println!("right: {:?}, is_right={}", right, right.is_right());
let mapped = left.map_left(|x| x * 2);
println!("mapped: {:?}", mapped); // Left(84)
}
12.4 Trait Bound
基本语法
use std::fmt::Display;
// 等价写法
fn print_item_1<T: Display>(item: &T) { println!("{}", item); }
fn print_item_2(item: &impl Display) { println!("{}", item); }
// 多个约束
fn print_and_clone<T: Display + Clone>(item: &T) {
let clone = item.clone();
println!("原始: {}, 克隆: {}", item, clone);
}
// where 子句(更清晰)
fn complex<T, U, V>(t: &T, u: &U, v: &V) -> String
where
T: Display + Clone,
U: Debug + PartialEq,
V: Iterator<Item = String>,
{
format!("{}, {:?}", t, u)
}
fn main() {
print_and_clone(&42);
print_and_clone(&"hello".to_string());
}
约束继承
use std::fmt::{Debug, Display};
trait Printable: Display + Debug {
fn print(&self) {
println!("Display: {}", self);
println!("Debug: {:?}", self);
}
}
// 为满足 Display + Debug 的类型自动实现
#[derive(Debug)]
struct MyType(i32);
impl Display for MyType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "MyType({})", self.0)
}
}
impl Printable for MyType {} // 使用默认实现
fn main() {
let x = MyType(42);
x.print();
}
12.5 泛型与性能
单态化(Monomorphization)
// 编译器会为每个使用的具体类型生成专用代码
fn add<T: std::ops::Add<Output = T>>(a: T, b: T) -> T {
a + b
}
fn main() {
// 编译器生成:
// fn add_i32(a: i32, b: i32) -> i32 { a + b }
// fn add_f64(a: f64, b: f64) -> f64 { a + b }
let int_sum = add(1, 2);
let float_sum = add(1.5, 2.5);
println!("整数: {}, 浮点: {}", int_sum, float_sum);
}
注意: 泛型的性能与手写具体类型完全相同,没有运行时开销。代价是编译时间更长、二进制文件更大。
12.6 常量泛型(Const Generics)
// 泛型常量参数(Rust 1.51+)
fn display_array<T: std::fmt::Debug, const N: usize>(arr: &[T; N]) {
println!("数组[{}]: {:?}", N, arr);
}
#[derive(Debug)]
struct Matrix<T, const ROWS: usize, const COLS: usize> {
data: [[T; COLS]; ROWS],
}
impl<T: Default + Copy, const ROWS: usize, const COLS: usize> Matrix<T, ROWS, COLS> {
fn new() -> Self {
Self {
data: [[T::default(); COLS]; ROWS],
}
}
}
impl<T: std::fmt::Display, const ROWS: usize, const COLS: usize> Matrix<T, ROWS, COLS> {
fn display(&self) {
for row in &self.data {
for (j, val) in row.iter().enumerate() {
if j > 0 { print!("\t"); }
print!("{}", val);
}
println!();
}
}
}
fn main() {
display_array(&[1, 2, 3]);
display_array(&[1, 2, 3, 4, 5]);
let m: Matrix<i32, 2, 3> = Matrix::new();
m.display();
}
12.7 业务场景示例
泛型缓存系统
use std::collections::HashMap;
use std::hash::Hash;
use std::time::{Duration, Instant};
struct Cache<K, V> {
data: HashMap<K, CacheEntry<V>>,
ttl: Duration,
}
struct CacheEntry<V> {
value: V,
inserted_at: Instant,
}
impl<K: Eq + Hash, V: Clone> Cache<K, V> {
fn new(ttl: Duration) -> Self {
Self {
data: HashMap::new(),
ttl,
}
}
fn get(&mut self, key: &K) -> Option<&V> {
if let Some(entry) = self.data.get(key) {
if entry.inserted_at.elapsed() < self.ttl {
return Some(&entry.value);
}
}
self.data.remove(key);
None
}
fn set(&mut self, key: K, value: V) {
self.data.insert(key, CacheEntry {
value,
inserted_at: Instant::now(),
});
}
fn len(&self) -> usize {
self.data.len()
}
}
fn main() {
let mut cache: Cache<String, Vec<String>> = Cache::new(Duration::from_secs(60));
cache.set("users".to_string(), vec!["Alice".to_string(), "Bob".to_string()]);
if let Some(users) = cache.get(&"users".to_string()) {
println!("缓存命中: {:?}", users);
}
println!("缓存大小: {}", cache.len());
}
12.8 本章小结
| 要点 | 说明 |
|---|---|
| 泛型函数 | fn name<T>(arg: T) 适用于多种类型 |
| 泛型结构体 | struct Name<T> 存储泛型数据 |
| Trait bound | T: Trait 约束泛型必须实现特定 trait |
| where 子句 | 复杂约束时更清晰的写法 |
| 常量泛型 | const N: usize 编译时常量参数 |
| 单态化 | 编译时为每种类型生成专用代码,零开销 |
扩展阅读
- Rust Book - 泛型 — 官方教程
- Const Generics — 常量泛型参考