泛型与 Trait
泛型(Generics)
泛型允许编写适用于多种类型的代码,避免重复。
泛型函数
fn largest<T>(list: &[T]) -> &T { let mut largest = &list[0]; for item in list { if item > largest { // 这里需要 PartialOrd 约束 largest = item; } } largest } fn main() { let numbers = vec![34, 50, 25, 100, 65]; println!("最大: {}", largest(&numbers)); let chars = vec!['y', 'm', 'a', 'q']; println!("最大: {}", largest(&chars)); }
注意:以上代码需要加 PartialOrd 约束才能编译,我们稍后介绍。
泛型结构体
struct Point<T> { x: T, y: T, } fn main() { let integer = Point { x: 5, y: 10 }; // Point<i32> let float = Point { x: 1.0, y: 4.0 }; // Point<f64> }
泛型结构体多个类型参数
struct Point<T, U> { x: T, y: U, } fn main() { let both = Point { x: 5, y: 4.0 }; // Point<i32, f64> }
泛型枚举
enum Option<T> { Some(T), None, } enum Result<T, E> { Ok(T), Err(E), }
泛型方法
struct Point<T> { x: T, y: T, } impl<T> Point<T> { fn x(&self) -> &T { &self.x } } // 专门为 f64 类型实现的方法 impl Point<f64> { fn distance_from_origin(&self) -> f64 { (self.x.powi(2) + self.y.powi(2)).sqrt() } } fn main() { let p = Point { x: 5, y: 10 }; println!("p.x = {}", p.x()); let f = Point { x: 3.0, y: 4.0 }; println!("距离原点: {}", f.distance_from_origin()); }
Trait
Trait 定义共享行为,类似于其他语言的接口(interface)。
定义和实现 Trait
trait Summary { fn summarize(&self) -> String; } struct Article { title: String, author: String, content: String, } impl Summary for Article { fn summarize(&self) -> String { format!("《{}》- {}", self.title, self.author) } } struct Tweet { username: String, content: String, } impl Summary for Tweet { fn summarize(&self) -> String { format!("@{}: {}", self.username, self.content) } } fn main() { let article = Article { title: String::from("Rust 入门"), author: String::from("小明"), content: String::from("内容..."), }; println!("{}", article.summarize()); let tweet = Tweet { username: String::from("rust_fan"), content: String::from("学习 Rust 中!"), }; println!("{}", tweet.summarize()); }
默认实现
Trait 可以提供默认方法实现:
trait Summary { fn summarize(&self) -> String { String::from("(阅读更多...)") } } impl Summary for Article {} // 使用默认实现 impl Summary for Tweet { fn summarize(&self) -> String { format!("@{}: {}", self.username, self.content) } }
Trait 作为参数
// 方式一:impl Trait 语法 fn notify(item: impl Summary) { println!("通知: {}", item.summarize()); } // 方式二:Trait Bound 语法 fn notify<T: Summary>(item: T) { println!("通知: {}", item.summarize()); } // 多个参数 fn notify2(item1: impl Summary, item2: impl Summary) {} fn notify2<T: Summary>(item1: T, item2: T) {}
多重约束
use std::fmt::Display; // 同时要求 impl Summary + Display fn notify(item: impl Summary + Display) {} // 或使用 where 子句 fn some<T, U>(t: T, u: U) where T: Display + Clone, U: Clone + Summary, {}
返回 Trait
fn returns_summarizable() -> impl Summary { Article { title: String::from("Rust 泛型和 Trait"), author: String::from("老师"), content: String::from("内容..."), } }
常用标准库 Trait
| Trait | 用途 |
|---|---|
Clone | 提供 clone() 方法进行深拷贝 |
Copy | 标记类型使用按位复制(栈上类型) |
Debug | 提供 {:?} 格式化 |
Display | 提供 {} 格式化 |
PartialEq | 提供 ==, != 比较 |
PartialOrd | 提供 <, >, ⇐, >= 比较 |
Hash | 提供哈希计算 |
Iterator | 实现迭代器 |
本章实践
use std::fmt::Display; trait Greet { fn greet(&self) -> String; } struct Person { name: String, age: u8, } impl Greet for Person { fn greet(&self) -> String { format!("你好,我叫{},今年{}岁", self.name, self.age) } } fn print_greet(item: impl Greet + Display) { println!("{}", item.greet()); } fn main() { let p = Person { name: "小明".into(), age: 25, }; print_greet(p); }
本章小结
- 泛型允许编写类型无关的代码
impl<T>为泛型类型实现方法- Trait 定义共享行为,类似接口
impl Trait和T: Trait两种约束写法where子句简化复杂约束