文章目录
- 泛型函数
- 特征
- 特征泛型
Rust系列:初步⚙所有权⚙结构体和枚举类⚙函数进阶
泛型函数
Rust采纳了C++中的泛型机制,并且形式上也几乎借鉴了C++,示例如下
fn add<T: std::ops::Add<Output = T>>(a:T, b:T) -> T {
a + b
}
fn main() {
println!("add i32: {}", add(20, 30));
println!("add f64: {}", add(1.2, 1.2));
}
运行结果如下
add i32: 50
add f64: 2.4
可见add
函数对整型和浮点型都做出了正确的处理,这就是所谓的泛型。而理解了add
函数,其实就理解了泛型,下面分两步来阅读add
的定义,首先摘掉对T
的限制,写成如下形式
//这是个无法编译的伪代码
fn add<T>(a:T, b:T) -> T{
a+b
}
这样一来,add
函数就很容易理解了,输入一个T类型的a
和一个T类型的b
,其返回值也是T类型。但这里有一个Bug,即T类型在不确定的情况下,是不能使用加法的,所以在可以工作的泛型函数中,添加了对类型T的限制,即
T: std::ops::Add<Output = T>
很多情况下,我们希望输入的类型,需要有多种限制,不同限制之间可用加号链接。随着限制越来越多,这种尖括号的表示方法就显得过于臃肿了,为此可启用where关键字,如下面代码所示
use std::fmt;
fn print_add<T>(a:T, b:T)
where T: std::ops::Add<Output = T> + fmt::Display
{
println!("{}", a+b);
}
fn main() {
print_add(3,5)
}
其中,实现了fmt:Display
的类型可支持println!
函数的调用,运行结果如下
>rustc add.rs
>add.exe
8
特征
Rust并不支持结构体的继承,但通过trait,可以实现某种通用的功能函数,从而实现类似接口的功能。下面新建两个结构体Note和Noval,并且为二者统一添加一个Book功能
trait Book {
fn summarize(&self) -> String;
}
struct Note {
title: String, // 标题
author: String, // 作者
}
struct Noval{
title: String, // 标题
author: String, // 作者
finished: bool,
}
impl Book for Note{
fn summarize(&self)->String{
format!("{}做了{}笔记", self.author, self.title)
}
}
impl Book for Noval{
fn summarize(&self)->String{
let f = if self.finished {"已完结"} else {"未完结"};
format!("{}写了{},{}", self.author, self.title, f)
}
}
fn main() {
let note = Note{title:"Rust教程".to_string(),
author:"微小冷".to_string()};
let book = Noval{title:"呐喊".to_string(),
author:"鲁迅".to_string(),
finished:true};
println!("{}",note.summarize());
println!("{}",book.summarize());
}
编译结果如下。
微小冷做了Rust教程笔记
鲁迅写了呐喊,已完结
trait中可以直接对特征函数进行实现,这样在绑定特定的函数体时,可直接调用。下面在Book中再添加一个函数
trait Book {
fn summarize(&self) -> String;
fn print_summarize(&self){
println!("{}", self.summarize());
}
}
在绑定Book的过程中不用修改任何代码,然后在main函数中可直接调用这个函数。
note.print_summarize();
book.print_summarize();
特征泛型
对于传统函数,在参数传递时需要指明参数类型,从而完成了对参数的约束。
trait显然也可以起到参数约束的作用,而用trait来约束参数,便不需指明参数类型,从而也相当于起到了泛型的效果。下面新建一个函数,用于所有实现了Book功能的数据类型
fn summarize_book(b: &impl Book) {
b.print_summarize();
}
相应地主函数修改如下
fn main() {
let note = Note{title:"Rust教程".to_string(),
author:"微小冷".to_string()};
summarize_book(¬e)
}
运行结果为
微小冷做了Rust教程笔记
summarize_book(b: &impl Book)
可以写为更加泛型的形式,即
fn summarize_book<T: Book>(b:&T) {
b.print_summarize();
}