强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

第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 boundT: Trait 约束泛型必须实现特定 trait
where 子句复杂约束时更清晰的写法
常量泛型const N: usize 编译时常量参数
单态化编译时为每种类型生成专用代码,零开销

扩展阅读

  1. Rust Book - 泛型 — 官方教程
  2. Const Generics — 常量泛型参考