当前位置:   article > 正文

Rust教程5:泛型和特征_rust 特征泛型

rust 特征泛型

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));
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

运行结果如下

add i32: 50
add f64: 2.4
  • 1
  • 2

可见add函数对整型和浮点型都做出了正确的处理,这就是所谓的泛型。而理解了add函数,其实就理解了泛型,下面分两步来阅读add的定义,首先摘掉对T的限制,写成如下形式

//这是个无法编译的伪代码
fn add<T>(a:T, b:T) -> T{
    a+b
}
  • 1
  • 2
  • 3
  • 4

这样一来,add函数就很容易理解了,输入一个T类型的a和一个T类型的b,其返回值也是T类型。但这里有一个Bug,即T类型在不确定的情况下,是不能使用加法的,所以在可以工作的泛型函数中,添加了对类型T的限制,即

T: std::ops::Add<Output = T>
  • 1

很多情况下,我们希望输入的类型,需要有多种限制,不同限制之间可用加号链接。随着限制越来越多,这种尖括号的表示方法就显得过于臃肿了,为此可启用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)
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

其中,实现了fmt:Display的类型可支持println!函数的调用,运行结果如下

>rustc add.rs
>add.exe
8
  • 1
  • 2
  • 3

特征

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());
}
  • 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
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

编译结果如下。

微小冷做了Rust教程笔记
鲁迅写了呐喊,已完结

trait中可以直接对特征函数进行实现,这样在绑定特定的函数体时,可直接调用。下面在Book中再添加一个函数

trait Book {
    fn summarize(&self) -> String;
    fn print_summarize(&self){
        println!("{}", self.summarize());
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在绑定Book的过程中不用修改任何代码,然后在main函数中可直接调用这个函数。

    note.print_summarize();
    book.print_summarize();
  • 1
  • 2

特征泛型

对于传统函数,在参数传递时需要指明参数类型,从而完成了对参数的约束。

trait显然也可以起到参数约束的作用,而用trait来约束参数,便不需指明参数类型,从而也相当于起到了泛型的效果。下面新建一个函数,用于所有实现了Book功能的数据类型

fn summarize_book(b: &impl Book) {
    b.print_summarize();
}
  • 1
  • 2
  • 3

相应地主函数修改如下

fn main() {
    let note = Note{title:"Rust教程".to_string(), 
                    author:"微小冷".to_string()};
    summarize_book(&note)
}
  • 1
  • 2
  • 3
  • 4
  • 5

运行结果为

微小冷做了Rust教程笔记
  • 1

summarize_book(b: &impl Book)可以写为更加泛型的形式,即

fn summarize_book<T: Book>(b:&T) {
    b.print_summarize();
}
  • 1
  • 2
  • 3

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/黑客灵魂/article/detail/796958
推荐阅读
相关标签
  

闽ICP备14008679号