Skip to content

Rust - 泛型

泛型是 Rust 最强大的特性之一。它们允许你编写可处理多种不同数据类型的抽象、可重用代码。这减少了代码重复并提高了类型安全性,所有这些都不会带来任何运行时性能开销——这一原则被称为零成本抽象。

我们已经在 Vec<T>、Option<T> 和 Result<T, E> 等类型中看到了泛型的实际应用。其中的 <T> 是一个类型参数,是具体类型的占位符,将在使用泛型代码时指定。

你可以定义使用泛型类型参数的结构体。这对于创建可以存储任何类型值的容器或数据结构非常有用。

// 一个泛型 Point 结构体,可以为 x 和 y 存储任意两种类型。
struct Point<T, U> {
x: T,
y: U,
}
fn main() {
// 一个 x 和 y 都是整数的实例。
let integer_point = Point { x: 5, y: 10 };
println!("Integer point: x = {}, y = {}", integer_point.x, integer_point.y);
// 一个 x 是浮点数、y 是字符的实例。
let mixed_point = Point { x: 1.0, y: 'c' };
println!("Mixed point: x = {}, y = {}", mixed_point.x, mixed_point.y);
}

我们还可以编写作用于泛型类型的函数。为此,我们需要告诉编译器泛型类型 T 必须具备哪些能力。我们通过使用特性约束来实现这一点。

例如,如果我们要编写一个打印值的函数,类型 T 必须实现 Display 特性。语法 <T: Display> 将泛型类型 T 约束为只能是可显示的类型。

use std::fmt::Display;
// 这个函数接受一个泛型类型 `T`,它必须实现 `Display` 特性。
fn print_item<T: Display>(item: T) {
println!("Here is your item: {}", item);
}
fn main() {
print_item(10_u32); // 适用于 u32
print_item("Hello, Generics!"); // 适用于 &str
print_item(3.14); // 适用于 f64
}

一个特性定义了一组类型必须实现的方法。它类似于其他语言中的接口。特性是我们在 Rust 中实现抽象和多态的方式。它们允许不同类型共享相同的行为。

让我们定义一个 Summary 特性,它提供对象数据的摘要。

// 1. 定义特性
pub trait Summary {
// 一个抽象方法;实现该特性的类型必须提供其方法体。
fn summarize_author(&self) -> String;
// 一个默认方法;实现该特性的类型可以使用或覆盖它。
fn summarize(&self) -> String {
format!("(Read more from {}...)", self.summarize_author())
}
}
// 2. 定义我们的结构体
pub struct NewsArticle {
pub headline: String,
pub author: String,
}
pub struct Tweet {
pub username: String,
pub content: String,
}
// 3. 为我们的结构体实现特性
impl Summary for NewsArticle {
fn summarize_author(&self) -> String {
format!("@{}", self.author)
}
}
impl Summary for Tweet {
fn summarize_author(&self) -> String {
format!("@{}", self.username)
}
// 我们也可以覆盖默认方法
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
}
// 4. 使用特性
fn main() {
let tweet = Tweet {
username: String::from("rustacean"),
content: String::from("I love traits!"),
};
let article = NewsArticle {
headline: String::from("Rust 1.70 Released!"),
author: String::from("The Rust Team"),
};
println!("New tweet: {}", tweet.summarize());
println!("New article: {}", article.summarize());
}

对于标准库中许多常见的特性(例如用于打印的 Debug、用于复制的 Clone、用于比较的 PartialEq),你无需手动编写实现。Rust 提供了 #[derive] 属性来为你自动生成实现。这极大地节省了时间,也是 Rust 中非常常见的做法。

// 为此结构体自动实现 Debug、Clone 和 PartialEq。
#[derive(Debug, Clone, PartialEq)]
struct Rectangle {
width: u32,
height: u32,
}
fn main() {
let r1 = Rectangle { width: 30, height: 50 };
let r2 = r1.clone(); // 我们可以克隆它,因为有 `#[derive(Clone)]`
// 我们可以使用 `{:?}` 打印它,因为有 `#[derive(Debug)]`
println!("Rectangle 1: {:?}", r1);
// 我们可以比较它们,因为有 `#[derive(PartialEq)]`
println!("Are they equal? {}", r1 == r2);
}