趣味学RUST基础篇(泛型)
《Rust 代码瘦身营》:告别重复,拥抱“抽象之美”!
“欢迎来到《Rust 代码瘦身营》!今天我们要帮一群‘臃肿’的代码减掉重复的脂肪,练出健美的‘泛型肌肉’!”
场景一:程序员的“复制粘贴”噩梦
想象你写了两个函数:
fn largest_i32(list: &[i32]) -> i32 {let mut largest = list[0];for &item in list {if item > largest {largest = item;}}largest
}fn largest_char(list: &[char]) -> char {let mut largest = list[0];for &item in list {if item > largest {largest = item;}}largest
}
“cool!这两个函数长得一模一样,除了一个处理 i32
,一个处理 char
。”
这就像你为“穿蓝衣服的人”和“穿红衣服的人”分别写了一套完全相同的操作手册——太浪费了!
解法:提取“通用逻辑”——泛型登场!
Rust 说:
“别慌!我们有泛型(Generics)——
它就像一个‘万能模板’,可以代替任何具体类型!”
我们把上面两个函数合并成一个:
fn largest<T>(list: &[T]) -> T {let mut largest = list[0];for &item in list {if item > largest { // 这里有问题!先别急largest = item;}}largest
}
T
是什么?
它是一个“类型变量”——你可以把它想象成“某种类型,具体是谁,编译时再定”。
调用它时:
let nums = vec![1, 2, 3];
let max_num = largest(&nums); // T 自动变成 i32let chars = vec!['a', 'b', 'c'];
let max_char = largest(&chars); // T 自动变成 char
成功瘦身!一个函数,搞定所有类型!
泛型还能用在哪儿?
不只函数,结构体、枚举也能用泛型!
1. 结构体泛型
struct Point<T, U> {x: T,y: U,
}let p1 = Point { x: 1, y: 2.5 }; // T=i32, U=f64
let p2 = Point { x: "hello", y: 'a' }; // T=&str, U=char
就像“万能收纳盒”:
你想放啥类型,它就变成啥类型!
2. 枚举泛型
还记得 Option<T>
和 Result<T, E>
吗?
enum Option<T> {Some(T),None,
}enum Result<T, E> {Ok(T),Err(E),
}
它们本身就是泛型的典范!
一个Option
,能装i32
、String
、File
……无所不能!
但泛型不是“万能胶”——它需要“行为保证”
回到 largest<T>
函数:
if item > largest { ... } // 编译错误!
问题来了:
“所有类型都能用
>
比较吗?”
比如,你能比较两个 String
吗?可以。
但你能比较两个 File
吗?不行!
所以 Rust 说:
“你得告诉我:
T
必须支持‘比较’这个行为!”
这就引出了——
Trait:行为的“合同”
Trait 就像一份“能力合同”:
trait Comparable {fn compare(&self, other: &Self) -> bool;
}
但我们不用自己写,Rust 标准库有现成的:
use std::cmp::PartialOrd;fn largest<T: PartialOrd>(list: &[T]) -> T {let mut largest = list[0];for &item in list {if item > largest { // 现在可以了!largest = item;}}largest
}
T: PartialOrd
意思是:
“T
必须实现了PartialOrd
trait,也就是支持比较操作!”
就像招聘:
“我们招程序员,但必须会写代码!”(会写代码 = trait)
终极挑战:生命周期(Lifetimes)——引用的“时间管理大师”
泛型不只是类型,还有时间!
看这段代码:
fn longest(x: &str, y: &str) -> &str {if x.len() > y.len() { x } else { y }
}
看起来没问题?但 Rust 会报错:
“我怎么知道返回的引用,比
x
和y
活得更久?”
这就像问:
“你借了两本书,哪本借得更久?但你还没说你什么时候还!”
所以 Rust 引入了 生命周期参数:
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {if x.len() > y.len() { x } else { y }
}
'a
是一个“生命周期变量”:
它保证x
、y
和返回值都“活”得一样久。
就像约会:
“我们仨的见面时间,不能超过最短的那个能待的时间。”
总结:三大法宝,一网打尽
工具 | 作用 | 类比 |
---|---|---|
泛型 <T> | 抽象类型,避免重复代码 | 万能模板 |
Trait | 约束泛型的行为 | 能力合同 |
生命周期 'a | 管理引用的存活时间 | 时间管理大师 |
“恭喜各位!经过今天的《Rust 代码瘦身营》,你已经掌握了:
用泛型消灭重复代码
用 Trait 确保类型有正确行为
用生命周期防止悬垂引用”