泛型类型, Traits, 生命期
https://doc.rust-lang.org/book/ch10-00-generics.html
任何编程语言都有有效处理代码重复的手段. 在 Rust 中提供的类似方式是泛型.
Rust 支持泛型类和泛型函数, 比如 Vec<T>
. 此外, Trait
也可以定义为泛型的, Rust 中的 Trait 就是其它语言中的 interface 概念.
在 Rust 中还有一个核心概念是 lifetime. 下面分别来看.
泛型数据类型
泛型函数语法如下:
/// 找列表中最大值
fn largest<T>(list: &[T]) -> &T where T: std::cmp::PartialOrd{
let mut largest = &list[0];
for item in list {
if item > largest {
largest = item;
}
}
largest
}
fn main() {
let number_list = vec![34, 50, 25, 100, 65];
let result = largest(&number_list);
println!("The largest number is {}", result);
let char_list = vec!['y', 'm', 'a', 'q'];
let result = largest(&char_list);
println!("The largest char is {}", result);
}
泛型类型语法如下:
struct Point<T> {
x: T,
y: T,
}
fn main() {
let integer = Point { x: 5, y: 10 };
let float = Point { x: 1.0, y: 4.0 };
}
// 多个泛型参数
struct MyValues<T, U> {
v1: T,
v2: U,
}
// enum 中的泛型参数
enum MyResult<T, E> {
Some(T),
Err(E),
}
// 在方法实现中使用泛型
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
}
// 某个特定泛型参数类型的实现
impl Point<f32> {
fn sqrt(&self) -> f32 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}
泛型性能
Rust 的一个特点就是零开销抽象, Rust 在实现泛型时, 是通过编译的时候对泛型展开来实现的. 在展开过程中, 编译器会查找所有使用到对应泛型的地方, 并按照实际类型将泛型展开为具体类型代码.
比如下面的代码:
fn main() {
let integer = Option_i32::Some(5);
let float = Option_f64::Some(5.0);
}
当 Rust 编译这段代码时, 编译器读取代码中所有使用 Option<T>
的地方, 这里会发现有 Option<i32>
和 Option<f64>
两处, 因此展开后的实际代码中, 会包含 Option
类型的两个定义:
enum Option_i32 {
Some(i32),
None,
}
enum Option_f64 {
Some(f64),
None,
}
fn main() {
let integer = Option_i32::Some(5);
let float = Option_f64::Some(5.0);
}
可以注意到展开后的类型命名, 且正因为 Rust 编译器会将泛型自动展开为具体类型, 因此我们在使用泛型抽象时, 泛型抽象本身是零开销的.
Trait
: 定义同有行为
Rust 中 Trait 即其它语言中的 interface 概念, 但和 interface 有细微差别.
通过 Trait
可以提供一种对共有行为的抽象.
简单的 Trait 定义:
pub trait Summary {
fn summarize(&self) -> String;
}
某个类型对 Trait 实现:
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 Tweet {
fn summarize(&self) -> String {
format!("{}: {}", self.username, self.content)
}
}
在特定类型上实现 Trait 的语法如上所示, 即 impl Trait for 类型 {..}
.
在 实现 Trait 的时候有一个限制: 无法对本 crate 外部类型实现本 crate 外部的 Trait. 比如我们可以在定义 trait 的 crate 中在 Vec
上实现该协议, 也可以在本地的 MyPoint
类型上实现外部的 Trait, 但无法在引入的类型上实现引入的 Trait.
Rust 引入这个限制的原因是: 确保其它的用户或开发者自己不会通过实现 Trait 的方式把对方的代码搞坏, 因为上面的限制保证了只能对自己的类型或自己的 Trait 才能提供 Trait 实现. (比如无法对 Vec
再提供 Display
的实现, 因为这两个都不是我们自己的)
可以提供 Trait 的默认实现:
pub trait Summary {
fn summarize(&self) -> String {
String::from("(Read more...)")
}
}
如果某个类型想实现有默认实现的 Trait, 则:
// 如果想使用默认实现
impl Summary for MyType { }
// 如果想覆盖默认实现
impl Summary for MyType {
fn summarize(&self) -> String {
String::from("(More ...)")
}
}