内容总结自《The Rust Programing Language》
首先简单说一下泛型:这个基础和C++的模板大概类似,从语法编译层面提供一种接收任意类型的手段,需要知道的是泛型在编译时会进行
单态化
处理,所以泛型是不会增加运行时负担的。熟悉C++的前提下,泛型应该是看一下就可以很快入门,这里不赘述。
Rust通过 trait 以一种抽象的方式定义共享的行为。可以使用 trait bounds 指定泛型是任何拥有特定行为的类型,trait就类似其他语言的接口。trait 定义就是一种将方法签名组合起来的方法,目的是定义一个实现某些目的所必需的行为的集合。
贴一下相干性
的概念:(感觉是常识)
不能为外部类型实现外部 trait。例如,不能在 aggregator
crate 中为 Vec<T>
实现 Display
trait。这是因为 Display
和 Vec<T>
都定义于标准库中,它们并不位于 aggregator
crate 本地作用域中。这个限制是被称为 相干性(coherence) 的程序属性的一部分,或者更具体的说是 孤儿规则(orphan rule),其得名于不存在父类型。这条规则确保了其他人编写的代码不会破坏你代码,反之亦然。
//trait定义的简单例子
pub trait Summary {
fn summarize_author(&self) -> String;
//trait方法支持默认实现
fn summarize(&self) -> String {
format!("(Read more from {}...)", self.summarize_author())
}
}
pub struct Tweet {
pub username: String,
pub content: String,
pub reply: bool,
pub retweet: bool,
}
impl Summary for Tweet {
fn summarize_author(&self) -> String {
format!("@{}", self.username)
}
}
let tweet = Tweet {
username: String::from("horse_ebooks"),
content: String::from("of course, as you probably already know, people"),
reply: false,
retweet: false,
};
println!("1 new tweet: {}", tweet.summarize());
使用 trait 来接受多种不同类型的参数。
//该函数接收一个trait参数,那么只要是实现(impl)了Summary的类型都是有效参数
pub fn notify(item: impl Summary) {
println!("Breaking news! {}", item.summarize());
}
//trait语法糖 trait bound
//这里强制item1,item2必须是相同的具体类型
pub fn notify<T: Summary>(item1: T, item2: T) {
//使用+号可以同时实现多个trait
pub fn notify(item: impl Summary + Display) {}//impl写法
pub fn notify<T: Summary + Display>(item: T) {}//trait bound写法
//通过where简化trait bound
//显得杂乱无章
fn some_function<T: Display + Clone, U: Clone + Debug>(t: T, u: U) -> i32 {}
//使用where之后好看多了
fn some_function<T, U>(t: T, u: U) -> i32
where T: Display + Clone,
U: Clone + Debug
{}
//一个使用trait boud编写函数的例子
fn largest<T: PartialOrd + Copy>(list: &[T]) -> T {
let mut largest = list[0];
for &item in list.iter() {
if item > largest {
largest = item;
}
}
largest
}
//使用trait bound有条件的实现
//通过使用带有 trait bound 的泛型参数的 impl 块,可以有条件地只为那些实现了特定 trait 的类型实现方法。
//示例中的类型 Pair<T> 总是实现了 new 方法,
//不过只有那些为 T 类型实现了 PartialOrd trait (来允许比较)
//和 Display trait (来启用打印)的 Pair<T> 才会实现 cmp_display 方法:
#![allow(unused)]
fn main() {
use std::fmt::Display;
struct Pair<T> {
x: T,
y: T,
}
impl<T> Pair<T> {
fn new(x: T, y: T) -> Self {
Self {
x,
y,
}
}
}
impl<T: Display + PartialOrd> Pair<T> {
fn cmp_display(&self) {
if self.x >= self.y {
println!("The largest member is x = {}", self.x);
} else {
println!("The largest member is y = {}", self.y);
}
}
}
}
trait 和 trait bound 让我们使用泛型类型参数来减少重复,并仍然能够向编译器明确指定泛型类型需要拥有哪些行为。因为我们向编译器提供了 trait bound 信息,它就可以检查代码中所用到的具体类型是否提供了正确的行为。