泛型
- 提高代码复用能力
- 泛型是具体类型或其他属性的抽象代替
- 编写的代码不是最终的代码、而是一种模板,里面有一些“占位符”
- 编译器在编译时将“占位符”替换为具体的类型。
函数泛型
例如:fn largest<T>(list:&[T]) -> T{ ... }
结构体泛型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| struct User<T>{ x: T, y: T, }
struct Users<T, U>{ x: T, y: U, }
fn main() { let integer = User {x: 5, y: 10}; let double = User {x: 1.0, y: 2.0}; let mix = User {x: 5, y: 10.0};
}
|
枚举泛型
1 2 3 4 5 6 7 8 9
| enum Option<T> { Some(T), None, }
struct Result<T, E>{ x: T, y: E, }
|
方法泛型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| struct Point<T> { x: T, y: T, }
impl<T> Point<T> { fn x(&self) -> &T { &self.x } }
impl Point<i32> { fn x1(&self) -> &i32 { &self.x } }
|
泛型的运行速度和普通代码运行速度一致,这是由于 Rust 在编译时将这些泛型单态化。即将他们的类型根据代码确定下来。
Trait
引入
- Trait 告诉 Rust 编译器,某种类型具有哪些并且可以与其他类型共享的功能。
- Trait:抽象的定义共享行为。
- Trait bounds(约束):泛型类型参数指定为实现了特定行为的类型。
- 类似于其他语言的接口
定义
把方法签名放在一起,来定义实现某种目的所必须的一组行为。
- 关键字:trait
- 只有方法签名,没有具体实现
- trait 可以有多个方法:每个方法签名占一行,以
;
结尾
- 实现该 trait 的类型必须提供具体的方法实现
在类型上实现 trait
- 关键字:`impl tarit_name for struct_name { … }
- 在 impl 的块里面,需要对 Trait 里的方法签名进行具体的实现。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| pub trait Summary { fn summarize(&self) -> String; }
pub struct NewsArticle { pub headline: String, pub location: String, pub author: String, pub content: String, }
impl Summary for NewsArticle { fn summarize(&self) -> String { format!("{}, by {} ({})", self.headline, self.author, self.location); } }
pub struct Tweet { pub username: String, pub content: String, pub reply: bool, pub retweet: bool, }
impl Summary for NewsArticle { fn summarize(&self) -> String { format!("{}:{}", self.username, self.content); } }
|
可以在某个类型上实现某个 trait 的前提条件是:这个类型或这个 trait 是在本地 crate 里定义的。
无法为外部类型来实现外部的 trait
默认实现
- 默认实现的方法可以调用 trait 中的其他方法,即使这些方法没有默认实现。
1 2 3 4 5 6 7 8 9
| pub trait Summary { fn summarize(&self) -> String { format!("(Read more...)"); } }
impl Summary for NewsArticle { }
|
默认实现是区别于接口的重要区分,我们可以在 Trait 的定义中实现默认实现,结构体可以是用这个默认实现。
Trait 作为参数
1 2 3
| pub fn notify(item: impl Summary) { println!("Breaking news {}", item.summarize()); }
|
1 2 3
| pub fn notify<T: Summary>(item: T) { println!("Breaking news {}", item.summarize()); }
|
1 2 3 4 5 6 7
| pub fn notify<T: Summary + Display>(item: T) { println!("Breaking news {}", item.summarize()); }
pub fn notify(item: impl Summary + Display) { println!("Breaking news {}", item.summarize()); }
|
- 简化 trait 约束,使用
where
,避免函数签名紊乱
1 2 3 4 5 6 7 8 9 10 11
| pub fn notify<T: Summary + Display, U: Clone + Debug>(a: T, b: U) -> String { println!("Breaking news {}", item.summarize()); }
pub fn notify<T, U>(a: T, b: U) -> String where T: Summary + Display, U: Clone + Debug, { println!("Breaking news {}", item.summarize()); }
|
Trait 作为返回类型
- impl Trait 只能返回确定的同一种类型,返回可能不同类型的代码会报错。
1 2 3 4 5
| pub fn notify1(s: &str) -> impl Summary { NewsArticle { .... } }
|
其他
- 在使用泛型类型参数的 impl 块上使用 Trait bound,我们可以有条件的为实现了特定 Trait 的类型来实现方法
1 2 3 4 5
| impl<T: Display + PartialOrd> Pair<T> { fn cmp_display(&self) { .. } }
|
- 可以为实现了其他 Tarit 的任意类型有条件的实现某个 Trait.
1 2 3
| impl<T: fmt::Display> ToString for T { .... }
|