泛型(Generics)是具体类型或其他属性的抽象替代。使用泛型可以编写适用于多种类型的代码,减少重复。
泛型的作用:
不使用泛型(重复代码):
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); }
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 }
enum Option<T> { Some(T), None, }
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")); }
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()); }
fn some_function<T, U>(t: T, u: U) -> i32 where T: Display + Clone, U: Clone + Debug, { // ... 0 }
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 }; }
单态化(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);
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()); }
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); }
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可以提供强大的抽象能力。