// 任何实现了 std::cmp::PartialOrd 和 Copy 的类型 T
// 都可以通过该函数求得数组切片 &[T] 中的最大值 T
fn largest<T: std::cmp::PartialOrd + Copy>(list: &[T]) -> T {
let mut largest = list[0];
for &item in list.iter() {
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);
}
const 泛型:值的泛型
// 我们定义了一个类型为 [T; N] 的数组
// 其中 T 是一个基于类型的泛型参数,这个和之前讲的泛型没有区别
// 而重点在于 N 这个泛型参数,它是一个基于值的泛型参数!因为它用来替代的是数组的长度。
fn display_array<T: std::fmt::Debug, const N: usize>(arr: [T; N]) {
println!("{:?}", arr);
}
fn main() {
let arr: [i32; 3] = [1, 2, 3];
display_array(arr);
let arr: [i32; 2] = [1, 2];
display_array(arr);
}
性能:在 Rust 中泛型是零成本的抽象,意味着你在使用泛型时,完全不用担心性能上的问题。
特征定义了一个可以被共享的行为,只要实现了特征,你就能使用该行为
**孤儿规则:**如果你想要为类型 A
实现特征 T
,那么 A
或者 T
至少有一个是在当前作用域中定义的
默认实现和重载
pub trait Summary {
fn summarize(&self) -> String {
String::from("(Read more...)")
}
}
// Post 使用默认实现
impl Summary for Post {}
// Weibo 重载了默认实现
impl Summary for Weibo {
fn summarize(&self) -> String {
format!("{}发表了微博{}", self.username, self.content)
}
}
使用特征作为函数参数
// 所有实现了 Summary Trait 的类型都可以作为该函数的参数
pub fn notify(item: &impl Summary) {
println!("Breaking news! {}", item.summarize());
}
特征约束
// 要求两个参数是同一类型,且实现了 Summary Trait
pub fn notify<T: Summary>(item1: &T, item2: &T) {}
// 要求参数同时实现 Summary 和 Display
pub fn notify<T: Summary + Display>(item: &T) {}
// 等价于
pub fn notify<T>(item: &T)
where T: Summary + Display
{}
Derive 派生特征 #[derive(Debug, PartialEq, Eq, Encode, Decode)]
dyn
为什么需要引入?
想返回所有实现了 Summary Trait
的类型
然而返回值只能有一个具体的类型
如果要实现返回不同的类型,需要使用特征对象
// 不能编译
fn returns_summarizable(switch: bool) -> impl Summary {
if switch {
Post {
title: String::from(
"Penguins win the Stanley Cup Championship!",
),
author: String::from("Iceburgh"),
content: String::from(
"The Pittsburgh Penguins once again are the best \\
hockey team in the NHL.",
),
}
} else {
Weibo {
username: String::from("horse_ebooks"),
content: String::from(
"of course, as you probably already know, people",
),
}
}
}
// 可以编译的完整代码
#[derive(Debug)]
pub struct Post {
pub title: String,
pub author: String,
pub content: String,
}
#[derive(Debug)]
pub struct Weibo {
pub username: String,
pub content: String
}
pub trait Summary: std::fmt::Debug {
fn summarize(&self) -> String {
String::from("(Read more...)")
}
}
// Post 使用默认实现
impl Summary for Post {}
// Weibo 重载了默认实现
impl Summary for Weibo {
fn summarize(&self) -> String {
format!("{}发表了微博{}", self.username, self.content)
}
}
// 返回任意实现了 Summary 的类型
fn returns_summarizable(switch: bool) -> Box<dyn Summary + 'static> {
if switch {
Box::new(Post {
title: String::from(
"Penguins win the Stanley Cup Championship!",
),
author: String::from("Iceburgh"),
content: String::from(
"The Pittsburgh Penguins once again are the best \\
hockey team in the NHL.",
),
})
} else {
Box::new(Weibo {
username: String::from("horse_ebooks"),
content: String::from(
"of course, as you probably already know, people",
),
})
}
}
fn main() {
println!("{:?}",returns_summarizable(false));
println!("{:?}",returns_summarizable(true));
}
特点
dyn
关键字只用在特征对象的类型声明上,在创建时无需使用 dyn
dyn
不能单独作为特征对象的定义,原因是特征对象可以是任意实现了某个特征的类型,编译器在编译期不知道该类型的大小,不同的类型大小是不同的。&dyn
和 Box<dyn>
在编译期都是已知大小(指),所以可以用作特征对象的定义。