从 Rust 基础到掌握 — 第 5 集
创建具有泛型、特征和生命周期的可重用 API
该博客上撰写的文章是出于教学目的而创建的。 另外,文章中的信息可能不正确,请谨慎。
泛型仅针对不同类型重用相同的规则,而特征定义类型必须提供的行为。 生命周期符号向编译器描述引用之间的关系。
用特质定义行为
trait Damageable {
fn is_alive(&self) -> bool;
fn take_damage(&mut self, amount: i32);
}
fn attack(target: &mut impl Damageable, damage: i32) {
if target.is_alive() {
target.take_damage(damage);
}
}
攻击可以使用实现 Damageable 的值,而无需知道具体类型。 与继承层次结构相比,特征更接近于所需行为的契约。
泛型和特征绑定
fn strongest<T>(values: &[T]) -> Option<&T>
where
T: Ord,
{
values.iter().max()
}
由于存在 T 实现 Ord 的条件,因此编译器知道这些值可以进行比较。 无效的类型组合在执行前会被拒绝。
特质实现
struct Monster {
health: i32,
}
impl Damageable for Monster {
fn is_alive(&self) -> bool {
self.health > 0
}
fn take_damage(&mut self, amount: i32) {
self.health = (self.health - amount).max(0);
}
}
通过分离数据和公共契约,可以在外部类型允许的范围内实现特征。
生活关系
fn longer<'a>(a: &'a str, b: &'a str) -> &'a str {
if a.len() >= b.len() { a } else { b }
}
'a 表示返回引用不能比两个输入引用寿命更长的关系。 它不是延长引用的实际寿命或创建运行时资源的函数。
大多数简单的生命周期都是由编译器推断的。 您应该首先检查 API 的所有权关系,看看返回值借用了哪些输入,而不是在发生错误时增加表示法。