Day 11: 泛型基础
1. 什么是泛型
Section titled “1. 什么是泛型”泛型(Generic)是编程语言中一种强大的抽象机制,允许你编写可适用于多种类型的代码,而无需重复编写相似的逻辑。在Rust中,泛型在编译期通过一种称为**单态化(Monomorphization)**的过程进行静态分发,这意味着泛型代码不会产生运行时开销。
泛型的核心优势在于:
- 代码复用:一次编写,适用于多种类型
- 类型安全:编译期检查,防止类型错误
- 零成本抽象:通过单态化,运行时性能与手动特化代码无异
2. 泛型函数
Section titled “2. 泛型函数”让我们从泛型函数开始。以下是一个简单的泛型函数,用于返回两个值中的较大者:
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]; let result = largest(&numbers); println!("最大值为: {}", result);
let chars = vec!['y', 'm', 'a', 'q']; let result = largest(&chars); println!("最大的字符是: {}", result);}注意函数签名中的 <T: PartialOrd>,这是trait约束(trait bound)的语法,表示 T 必须实现 PartialOrd trait 才能使用此函数。我们将在明天的教程中深入学习trait。
3. 泛型结构体
Section titled “3. 泛型结构体”泛型也可以用于结构体定义:
struct Point<T> { x: T, y: T,}
struct MixedPoint<T, U> { x: T, y: U,}
fn main() { let integer_point = Point { x: 5, y: 10 }; let float_point = Point { x: 1.0, y: 4.0 };
let mixed = MixedPoint { x: 5, y: 4.0 }; println!("整数点: ({}, {})", integer_point.x, integer_point.y); println!("浮点点: ({}, {})", float_point.x, float_point.y); println!("混合点: ({}, {})", mixed.x, mixed.y);}Point<T> 结构体有两个类型相同的字段,而 MixedPoint<T, U> 允许字段类型不同。
4. 泛型枚举
Section titled “4. 泛型枚举”枚举也可以使用泛型,这在标准库中有许多经典案例,例如 Option<T>:
enum Option<T> { Some(T), None,}
enum Result<T, E> { Ok(T), Err(E),}
fn main() { let some_number: Option<i32> = Some(5); let some_string: Option<&str> = Some("a string"); let no_number: Option<i32> = None;
let ok_result: Result<i32, &str> = Ok(5); let err_result: Result<i32, &str> = Err("error message");}Option<T> 是Rust中最常用的枚举之一,用于表示值可能存在或不存在的情况。Result<T, E> 用于错误处理。
5. Monomorphization(单态化)
Section titled “5. Monomorphization(单态化)”理解泛型的实现原理很重要。Rust编译器采用单态化策略处理泛型,这意味着:
每当使用泛型函数或类型时,编译器会生成一份该泛型代码的具体类型特化版本。
以 largest 函数为例:
- 当传入
&[i32]时,编译器生成largest_i32版本 - 当传入
&[char]时,编译器生成largest_char版本
这意味着:
- 优点:零运行时开销,性能等同于手写的特化代码
- 缺点:代码膨胀(code bloat),每种类型组合都会生成一份实例
// 编译器实际生成的代码类似于:fn largest_i32(list: &[i32]) -> &i32 { /* ... */ }fn largest_char(list: &[char]) -> &char { /* ... */ }6. 泛型方法的实现
Section titled “6. 泛型方法的实现”为泛型结构体或枚举实现方法时,需要在 impl 块中声明类型参数:
struct Point<T> { x: T, y: T,}
impl<T> Point<T> { fn new(x: T, y: T) -> Self { Point { x, y } }
fn x(&self) -> &T { &self.x }}
// 为特定类型的 Point 实现方法impl Point<f64> { fn distance_from_origin(&self) -> f64 { (self.x.powi(2) + self.y.powi(2)).sqrt() }}
fn main() { let p = Point::new(5, 10); println!("p.x = {}", p.x());}今天我们学习了Rust泛型编程的基础:
- 泛型函数:通过类型参数
<T>编写适用于多种类型的函数 - 泛型结构体和枚举:使用泛型定义可复用的数据结构
- Monomorphization:编译器将泛型代码静态生成为具体类型的特化版本,实现零成本抽象
- 泛型方法:在
impl块中使用泛型参数实现方法
泛型是Rust抽象层次编程的核心工具,明天我们将学习trait系统,它与泛型紧密配合,构成了Rust类型系统的基石。