泛型类型
> 掌握泛型结构体和枚举的定义方法,学习泛型实现和特定类型实现的技巧。
泛型结构体
定义泛型结构体
rust
▶ Run// 单个泛型参数
#[derive(Debug)]
struct Point<T> {
x: T,
y: T,
}
fn main() {
// 整数坐标
let integer = Point { x: 5, y: 10 };
println!("{:?}", integer);
// 浮点坐标
let float = Point { x: 1.0, y: 4.0 };
println!("{:?}", float);
// 类型推断
let p = Point { x: 5, y: 10 };
println!("{:?}", p);
// 显式标注
let p: Point<f64> = Point { x: 1.0, y: 2.0 };
}多个泛型参数
rust
▶ Run// 多个泛型参数,字段可以是不同类型
#[derive(Debug)]
struct Point<T, U> {
x: T,
y: U,
}
fn main() {
// 相同类型
let p1 = Point { x: 5, y: 10 }; // Point<i32, i32>
let p2 = Point { x: 1.0, y: 2.0 }; // Point<f64, f64>
// 不同类型
let p3 = Point { x: 5, y: 10.0 }; // Point<i32, f64>
let p4 = Point { x: "hello", y: 'A' }; // Point<&str, char>
let p5 = Point { x: vec![1, 2], y: "test" }; // Point<Vec<i32>, &str>
println!("p3: {:?}", p3);
println!("p4: {:?}", p4);
println!("p5: {:?}", p5);
}泛型枚举
rust
▶ Run// 标准库中的 Option 和 Result 都是泛型枚举
enum Option<T> {
Some(T),
None,
}
enum Result<T, E> {
Ok(T),
Err(E),
}
// 自定义泛型枚举
#[derive(Debug)]
enum Message<T> {
Quit, // 无数据
Move { x: T, y: T }, // 命名字段
Write(T), // 单个值
ChangeColor(T, T, T), // 多个值
}
fn main() {
// Option 示例
let some_number: Option<i32> = Some(42);
let none_number: Option<String> = None;
// Result 示例
let success: Result<i32, &str> = Ok(42);
let failure: Result<i32, &str> = Err("错误");
// Message 示例
let m1: Message<i32> = Message::Quit;
let m2: Message<f64> = Message::Move { x: 1.0, y: 2.0 };
let m3: Message<String> = Message::Write(String::from("hello"));
println!("m2: {:?}", m2);
println!("m3: {:?}", m3);
}泛型结构体的内存布局
Point<i32> 和 Point<f64> 在内存中是不同的:
Point<i32>:
┌─────┬─────┐
│ x │ y │
│ i32 │ i32 │ = 8 字节
│ 4B │ 4B │
└─────┴─────┘
Point<f64>:
┌─────┬─────┐
│ x │ y │
│f64 │f64 │ = 16 字节
│ 8B │ 8B │
└─────┴─────┘
Point<i32, f64>:
┌─────┬─────┐
│ x │ y │
│i32 │f64 │ = 16 字节(考虑对齐)
│ 4B │ 8B │
└─────┴─────┘
关键点:
• 每个具体类型组合都会生成独立的结构体
• 没有运行时类型信息(RTTI)开销
• 内存布局与手写专用代码完全相同泛型实现
impl 泛型参数
rust
▶ Run#[derive(Debug)]
struct Point<T> {
x: T,
y: T,
}
// 为所有 T 实现方法
impl<T> Point<T> {
// 访问器
fn x(&self) -> &T {
&self.x
}
fn y(&self) -> &T {
&self.y
}
// 获取两个坐标的引用
fn coordinates(&self) -> (&T, &T) {
(&self.x, &self.y)
}
}
// 需要特定 trait 约束的方法
impl<T: PartialOrd> Point<T> {
// 判断 x 是否大于 y
fn x_greater_than_y(&self) -> bool {
self.x > self.y
}
}
// Clone 约束
impl<T: Clone> Point<T> {
fn duplicate(&self) -> Self {
Point {
x: self.x.clone(),
y: self.y.clone(),
}
}
}
fn main() {
let p = Point { x: 5, y: 10 };
println!("x = {:?}", p.x());
println!("y = {:?}", p.y());
println!("coordinates = {:?}", p.coordinates());
println!("duplicated = {:?}", p.duplicate());
}特定类型的实现
rust
▶ Runstruct Point<T> {
x: T,
y: T,
}
// 为特定类型实现额外方法
impl Point<f32> {
fn distance_from_origin(&self) -> f32 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
fn rotate_90_degrees(&mut self) {
let new_x = -self.y;
let new_y = self.x;
self.x = new_x;
self.y = new_y;
}
}
impl Point<i32> {
fn manhattan_distance(&self) -> i32 {
self.x.abs() + self.y.abs()
}
}
fn main() {
let p1 = Point { x: 3.0, y: 4.0 };
println!("欧几里得距离:{}", p1.distance_from_origin()); // 5.0
let p2 = Point { x: 3, y: 4 };
println!("曼哈顿距离:{}", p2.manhattan_distance()); // 7
// p2.manhattan_distance() 只有 Point<i32> 才有
// p1.distance_from_origin() 只有 Point<f32> 才有
}多类型泛型的复杂实现
rust
▶ Runstruct Point<X, Y> {
x: X,
y: Y,
}
// 为所有 X, Y 实现
impl<X, Y> Point<X, Y> {
fn x(&self) -> &X {
&self.x
}
fn y(&self) -> &Y {
&self.y
}
}
// mixup 方法:混合两个不同 Point 的坐标
impl<X1, Y1> Point<X1, Y1> {
fn mixup<X2, Y2>(self, other: Point<X2, Y2>) -> Point<X1, Y2> {
Point {
x: self.x,
y: other.y,
}
}
}
// Clone 约束
impl<X: Clone, Y: Clone> Point<X, Y> {
fn clone_coords(&self) -> (X, Y) {
(self.x.clone(), self.y.clone())
}
}
fn main() {
let p1 = Point { x: 5, y: 10.4 }; // Point<i32, f64>
let p2 = Point { x: "Hello", y: 'c' }; // Point<&str, char>
let p3 = p1.mixup(p2); // Point<i32, char>
println!("p3.x = {:?}, p3.y = {}", p3.x(), p3.y());
// p1 已移动,但可以使用 clone_coords
// println!("{:?}", p1.clone_coords());
}带有 trait 约束的实现
rust
▶ Runuse std::fmt::Display;
struct Pair<T> {
x: T,
y: T,
}
impl<T> Pair<T> {
fn new(x: T, y: T) -> Self {
Self { x, y }
}
}
// 只有 T 实现 Display + PartialOrd 时才能调用
impl<T: Display + PartialOrd> Pair<T> {
fn cmp_display(&self) {
if self.x >= self.y {
println!("较大的值是:{}", self.x);
} else {
println!("较大的值是:{}", self.y);
}
}
}
// 只有 T 实现 Display 时才能打印
impl<T: Display> Pair<T> {
fn print_pair(&self) {
println!("({}, {})", self.x, self.y);
}
}
fn main() {
let p1 = Pair::new(5, 10);
p1.cmp_display(); // 较大的值是:10
p1.print_pair(); // (5, 10)
let p2 = Pair::new(3.14, 2.71);
p2.cmp_display(); // 较大的值是:3.14
}
---
## 小结
- 泛型结构体使用 `struct Name<T>` 定义,可以有多个泛型参数
- `impl<T> Name<T>` 为所有 T 实现方法,`impl Name<f32>` 为特定类型实现
- 泛型枚举如 `Option<T>` 和 `Result<T, E>` 是标准库核心类型
- 不同具体类型组合会在编译时生成不同的结构体
- 带 trait 约束的方法只为满足条件的类型提供
## 练习题
详见:[练习题](../../exercises/15-generics)