
一套代码走天下:泛型函数、结构体、枚举全解析
你有没有写过这种代码:一个函数处理 i32,另一个函数处理 f64,再写一个处理 String……然后发现这三个函数的逻辑一模一样,只是类型不同!
我当时就这么干过,写了五个几乎一样的函数,只是类型不同。后来同事问我:"你是复制粘贴狂魔吗?"
泛型就是来拯救你的!它让你用一套代码处理多种类型,就像洗衣机上的"万能模式"——不管洗什么衣服,都能搞定(虽然可能没有专用模式洗得那么好,但够用)。
Rust 的泛型特别强大,而且是在编译时完成的,没有运行时开销。这意味着你用了泛型,性能和手写专用代码一样快!编译器帮你干了所有脏活累活。
泛型就是"类型参数化"。普通函数是这样的:
fn add_i32(a: i32, b: i32) -> i32 {
a + b
}
泛型函数是这样的:
fn add<T>(a: T, b: T) -> T {
a + b // ❌ 等等,这不能编译!后面说为什么
}
<T> 就是类型参数,可以是任何类型。T 是"Type"的缩写,你也可以用别的名字,但大家都用 T,你也别搞特殊。
// 最简单的泛型函数
fn identity<T>(x: T) -> T {
x
}
fn main() {
let a = identity(); // T 推断为 i32
let b = identity("hello"); // T 推断为 &str
let c = identity::<f64>(3.14); // 显式指定 T
}
fn pair<T, U>(a: T, b: U) -> (T, U) {
(a, b)
}
fn main() {
let p = pair(, "hello"); // (i32, &str)
let q = pair(3.14, true); // (f64, bool)
}
// 单个泛型参数
struct Point<T> {
x: T,
y: T,
}
// 多个泛型参数
struct Point2<T, U> {
x: T,
y: U,
}
fn main() {
let p1 = Point { x: , y: }; // Point<i32>
let p2 = Point { x: 1.0, y: 4.0 }; // Point<f64>
let p3 = Point2 { x: , y: 10.0 }; // Point2<i32, f64>
}
// Option 和 Result 就是泛型枚举
enum MyOption<T> {
Some(T),
None,
}
enum MyResult<T, E> {
Ok(T),
Err(E),
}
fn main() {
let a: MyOption<i32> = MyOption::Some();
let b: MyOption<&str> = MyOption::None;
let c: MyResult<i32, &str> = MyResult::Ok();
let d: MyResult<i32, &str> = MyResult::Err("出错了");
}
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
}
fn y(&self) -> &T {
&self.y
}
}
// 只为特定类型实现方法
impl Point<f32> {
fn distance_from_origin(&self) -> f32 {
(self.x.powi() + self.y.powi()).sqrt()
}
}
fn main() {
let p = Point::new(, );
println!("x = {}", p.x());
let p2 = Point::new(3.0, 4.0);
println!("距离原点:{}", p2.distance_from_origin());
}
use std::fmt::Display;
// T 必须实现 Display trait
fn print_item<T: Display>(item: T) {
println!("{}", item);
}
// 多个约束
fn print_and_debug<T: Display + std::fmt::Debug>(item: T) {
println!("{}", item);
println!("{:?}", item);
}
// where 子句(复杂约束时用)
fn complex_function<T, U>(t: T, u: U)
where
T: Display + Clone,
U: Clone + std::fmt::Debug,
{
println!("{}", t);
let _t2 = t.clone();
println!("{:?}", u);
let _u2 = u.clone();
}
fn main() {
print_item(); // ✅ i32 实现 Display
print_item("hello"); // ✅ &str 实现 Display
// print_item(vec![1,2]); // ❌ Vec 没实现 Display
}
错误 1:泛型函数里瞎操作
fn add<T>(a: T, b: T) -> T {
a + b // ❌ 编译错误!
}
编译器说:
binary operation `+` cannot be applied to type `T`
解释: 不是所有类型都能相加!你得告诉编译器 T 必须支持加法。
正确做法:
use std::ops::Add;
fn add<T>(a: T, b: T) -> T
where
T: Add<Output = T>
{
a + b
}
错误 2:泛型结构体方法不匹配
struct Point<T> {
x: T,
y: T,
}
impl Point<f32> {
fn new(x: i32, y: i32) -> Self { // ❌ 类型不匹配!
Point { x, y }
}
}
编译器说:
mismatched types: expected f32, found i32
正确做法:
impl Point<f32> {
fn new(x: f32, y: f32) -> Self {
Point { x, y }
}
}
错误 3:忘记加 Trait 约束
fn print_all<T>(items: &[T]) {
for item in items {
println!("{}", item); // ❌ 编译错误!
}
}
编译器说:
the trait `Display` is not implemented for `T`
正确做法:
use std::fmt::Display;
fn print_all<T: Display>(items: &[T]) {
for item in items {
println!("{}", item);
}
}
泛型函数里的类型 T 不能随便操作,必须通过 Trait 约束告诉编译器 T 支持什么操作。
// ❌ 这样不行
fn double<T>(x: T) -> T {
x *
}
// ✅ 这样才行
fn double<T>(x: T) -> T
where
T: std::ops::Mul<Output = T> + From<u8>
{
x * T::from(2u8)
}
每个具体类型都会生成一份代码,类型太多会增加编译时间和二进制大小。
// 这会生成多份代码
let a = identity(); // i32 版本
let b = identity(1.0); // f64 版本
let c = identity("hi"); // &str 版本
解决方法:用 Trait 对象(后面会讲)。
struct Ref<T> {
value: &T, // ❌ 编译错误!缺少生命周期
}
// 正确写法
struct Ref<'a, T> {
value: &'a T,
}
引用类型必须加生命周期参数!
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 len(&self) -> usize {
self.items.len()
}
}
fn main() {
// 整数栈
let mut int_stack = Stack::new();
int_stack.push();
int_stack.push();
int_stack.push();
println!("{:?}", int_stack.pop()); // Some(3)
// 字符串栈
let mut str_stack = Stack::new();
str_stack.push("hello");
str_stack.push("world");
println!("{:?}", str_stack.pop()); // Some("world")
}
struct Node<T> {
value: T,
next: Option<Box<Node<T>>>,
}
impl<T> Node<T> {
fn new(value: T) -> Self {
Node { value, next: None }
}
fn with_next(value: T, next: Node<T>) -> Self {
Node {
value,
next: Some(Box::new(next))
}
}
}
// 简单的泛型链表
struct LinkedList<T> {
head: Option<Box<Node<T>>>,
}
impl<T> LinkedList<T> {
fn new() -> Self {
LinkedList { head: None }
}
fn prepend(&mut self, value: T) {
let new_node = Box::new(Node {
value,
next: self.head.take(),
});
self.head = Some(new_node);
}
fn pop(&mut self) -> Option<T> {
self.head.take().map(|node| {
self.head = node.next;
node.value
})
}
}
fn main() {
let mut list = LinkedList::new();
list.prepend();
list.prepend();
list.prepend();
println!("{:?}", list.pop()); // Some(1)
println!("{:?}", list.pop()); // Some(2)
}
use std::collections::HashMap;
use std::hash::Hash;
struct Cache<K, V> {
data: HashMap<K, V>,
capacity: usize,
}
impl<K: Eq + Hash + Clone, V: Clone> Cache<K, V> {
fn new(capacity: usize) -> Self {
Cache {
data: HashMap::new(),
capacity,
}
}
fn get(&self, key: &K) -> Option<V> {
self.data.get(key).cloned()
}
fn put(&mut self, key: K, value: V) {
// 简单实现:满了就清空
if self.data.len() >= self.capacity && !self.data.contains_key(&key) {
self.data.clear();
}
self.data.insert(key, value);
}
fn contains(&self, key: &K) -> bool {
self.data.contains_key(key)
}
fn len(&self) -> usize {
self.data.len()
}
}
fn main() {
let mut cache = Cache::new();
cache.put("a", );
cache.put("b", );
cache.put("c", );
println!("{:?}", cache.get(&"a")); // Some(1)
println!("{:?}", cache.get(&"d")); // None
}
use std::ops::{Add, Sub, Mul, Div};
struct Calculator<T> {
value: T,
}
impl<T> Calculator<T>
where
T: Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T> + From<u8> + Copy,
{
fn new(initial: T) -> Self {
Calculator { value: initial }
}
fn add(&mut self, other: T) {
self.value = self.value + other;
}
fn sub(&mut self, other: T) {
self.value = self.value - other;
}
fn mul(&mut self, other: T) {
self.value = self.value * other;
}
fn div(&mut self, other: T) {
self.value = self.value / other;
}
fn get(&self) -> T {
self.value
}
}
fn main() {
let mut calc = Calculator::new(10.0);
calc.add(5.0);
calc.mul(2.0);
calc.sub(5.0);
calc.div(3.0);
println!("结果:{}", calc.get()); // 10.0
}

Vec<T>、Option<T>、Result<T, E> 都是泛型下篇预告: 泛型虽然强大,但每次都要写一堆 Trait 约束,烦不烦?Trait 就是来拯救你的!下篇我们讲讲 Trait 到底是什么,为什么它是 Rust 最强大的特性之一!