目录

第十二章 泛型

12.1 什么是泛型

泛型(Generics)是具体类型或其他属性的抽象替代。使用泛型可以编写适用于多种类型的代码,减少重复。

泛型的作用:

12.2 泛型函数

提取最大值

不使用泛型(重复代码):

fn largest_i32(list: &[i32]) -> i32 {
    let mut largest = list[0];
    for &item in list.iter() {
        if item > largest {
            largest = item;
        }
    }
    largest
}
 
fn largest_char(list: &[char]) -> char {
    let mut largest = list[0];
    for &item in list.iter() {
        if item > largest {
            largest = item;
        }
    }
    largest
}

使用泛型:

fn largest<T: PartialOrd>(list: &[T]) -> &T {
    let mut largest = &list[0];
    for item in list.iter() {
        if item > largest {
            largest = item;
        }
    }
    largest
}
 
fn main() {
    let numbers = vec![34, 50, 25, 100, 65];
    let result = largest(&numbers);
    println!("最大数字是{}", result);
 
    let chars = vec!['y', 'm', 'a', 'q'];
    let result = largest(&chars);
    println!("最大字符是{}", result);
}

12.3 泛型结构体

定义泛型结构体

struct Point<T> {
    x: T,
    y: T,
}
 
fn main() {
    let integer = Point { x: 5, y: 10 };
    let float = Point { x: 1.0, y: 4.0 };
}

不同字段不同类型:

struct Point<T, U> {
    x: T,
    y: U,
}
 
fn main() {
    let both_integer = Point { x: 5, y: 10 };
    let both_float = Point { x: 1.0, y: 4.0 };
    let integer_and_float = Point { x: 5, y: 4.0 };
}

泛型结构体的方法

struct Point<T> {
    x: T,
    y: T,
}
 
impl<T> Point<T> {
    fn x(&self) -> &T {
        &self.x
    }
}
 
// 只为特定类型实现方法
impl Point<f32> {
    fn distance_from_origin(&self) -> f32 {
        (self.x.powi(2) + self.y.powi(2)).sqrt()
    }
}

多类型参数的方法:

struct Point<T, U> {
    x: T,
    y: U,
}
 
impl<T, U> Point<T, U> {
    fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {
        Point {
            x: self.x,
            y: other.y,
        }
    }
}
 
fn main() {
    let p1 = Point { x: 5, y: 10.4 };
    let p2 = Point { x: "Hello", y: 'c' };
 
    let p3 = p1.mixup(p2);
 
    println!("p3.x = {}, p3.y = {}", p3.x, p3.y);
    // p3.x = 5, p3.y = c
}

12.4 泛型枚举

Option<T>

enum Option<T> {
    Some(T),
    None,
}

Result<T, E>

enum Result<T, E> {
    Ok(T),
    Err(E),
}

自定义泛型枚举

enum Either<L, R> {
    Left(L),
    Right(R),
}
 
fn main() {
    let left: Either<i32, ()> = Either::Left(42);
    let right: Either<(), String> = Either::Right(String::from("hello"));
}

12.5 泛型约束(Trait Bounds)

单个约束

fn largest<T: PartialOrd>(list: &[T]) -> &T {
    // ...
}

多个约束

use std::fmt::Display;
 
fn notify<T: Display + Clone>(item: T) {
    println!("{}", item.clone());
}
 
// 使用where子句(更清晰)
fn notify<T>(item: T)
where
    T: Display + Clone,
{
    println!("{}", item.clone());
}

where子句

fn some_function<T, U>(t: T, u: U) -> i32
where
    T: Display + Clone,
    U: Clone + Debug,
{
    // ...
    0
}

12.6 默认泛型参数

struct Container<T, U = i32> {
    value: T,
    extra: U,
}
 
fn main() {
    let c1 = Container::<String, f64> {
        value: String::from("hello"),
        extra: 3.14,
    };
 
    let c2 = Container {
        value: String::from("world"),
        extra: 42,  // 使用默认类型i32
    };
}

12.7 泛型与性能

单态化(Monomorphization):

Rust在编译时将泛型代码转换为具体类型的代码,没有运行时开销。

// 源代码
let integer = Some(5);
let float = Some(5.0);
 
// 编译后等价于
enum Option_i32 {
    Some(i32),
    None,
}
 
enum Option_f64 {
    Some(f64),
    None,
}
 
let integer = Option_i32::Some(5);
let float = Option_f64::Some(5.0);

练习题

练习题12.1:泛型栈

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()
    }
 
    fn is_empty(&self) -> bool {
        self.items.is_empty()
    }
 
    fn size(&self) -> usize {
        self.items.len()
    }
}
 
fn main() {
    let mut stack = Stack::new();
    stack.push(1);
    stack.push(2);
    stack.push(3);
 
    println!("栈顶:{:?}", stack.peek());
    println!("弹出:{:?}", stack.pop());
    println!("大小:{}", stack.size());
}

练习题12.2:泛型Pair

struct Pair<T, U> {
    first: T,
    second: U,
}
 
impl<T, U> Pair<T, U> {
    fn new(first: T, second: U) -> Self {
        Pair { first, second }
    }
 
    fn swap(self) -> Pair<U, T> {
        Pair {
            first: self.second,
            second: self.first,
        }
    }
}
 
fn main() {
    let pair = Pair::new(1, "hello");
    println!("first: {}, second: {}", pair.first, pair.second);
 
    let swapped = pair.swap();
    println!("交换后:first: {}, second: {}", swapped.first, swapped.second);
}

练习题12.3:泛型查找

fn find<T: PartialEq>(list: &[T], target: &T) -> Option<usize> {
    for (i, item) in list.iter().enumerate() {
        if item == target {
            return Some(i);
        }
    }
    None
}
 
fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    match find(&numbers, &3) {
        Some(index) => println!("找到在索引{}", index),
        None => println!("未找到"),
    }
 
    let words = vec!["hello", "world", "rust"];
    match find(&words, &"rust") {
        Some(index) => println!("找到在索引{}", index),
        None => println!("未找到"),
    }
}

本章小结

本章学习了Rust的泛型:

泛型是Rust实现代码复用的重要机制,结合trait bounds可以提供强大的抽象能力。