Rust语法: 枚举,泛型,trait

这是我学习Rust的笔记,本文适合于有一定高级语言基础的开发者看不适合刚入门编程的人,对于一些概念像枚举,泛型等,不会再做解释,只写在Rust中怎么用。

文章目录

    • 枚举
      • 枚举的定义与赋值
      • 枚举绑定方法和函数
      • match匹配枚举
      • if let语句
      • Option
      • match pattern
        • 基本pattern
        • pattern守卫
    • 泛型
      • 泛型函数
      • 泛型结构体
      • 泛型枚举
      • 为结构体绑定泛型方法
    • trait
      • trait的定义与实现
      • 用trait指定定特定方法
      • impl中的trait约束

枚举

枚举的定义与赋值

枚举的定义格式如下:
enum 枚举名{
值1(附加类型),
值2(附加类型),…
}
其中,关联类型可以省去

例如要创建一个神经网络类型的枚举,就可以这样定义

enum NeuralNetwork {CNN,RNN,GAN,Transformer,GNN
}

下面是传参和创建的例子,其中引用的部分可以看后面的,所有权&生命周期这一部分。

enum NeuralNetwork {CNN,RNN,GAN,Transformer,GNN
}fn main(){let nn1 = NeuralNetwork::CNN; //创建一个NeuralNetwork类型的枚举,值为CNNlet nn2 = NeuralNetwork::Transformer;let nn3 = nn1;printnn(&nn3); //给函数传参printnn(&nn2);
}fn printnn(network: &NeuralNetwork){} //实参表明了需要一个NeuralNetwork类型的引用()

除此之外,枚举可以增加附类型

enum NeuralNetwork { // 所有的网络类型都带有一个附加类型,String表示具体的网络名CNN(String),RNN(String),GAN(String),Transformer(String),GNN(String)
}
enum Test{ // 所有的网络类型都带有一个附加类型,String表示具体的网络名e1,e2(String), e3{x: u32, y: f64}, //绑定了一个匿名结构体类型e4(u32, u32, u32) //绑定一个Tuple
}fn main(){let nn1 = NeuralNetwork::CNN(String::from("TextCNN")); let nn2 = NeuralNetwork::Transformer(String::from("Transformer-XL"));}

枚举绑定方法和函数

与结构体类型,对于枚举,Rust也允许使用impl关键字来绑定方法和函数

enum NeuralNetwork {CNN(String),RNN(String),GAN(String),Transformer(String),GNN(String)
}impl NeuralNetwork {fn make_cnn(s: String) -> NeuralNetwork{ //绑定一个函数,用于创建CNN类型枚举NeuralNetwork::CNN(s)}
}fn main(){let nn1 = NeuralNetwork::make_cnn(String::from("TextCNN"));let nn2 = NeuralNetwork::Transformer(String::from("Transformer-XL"));}

match匹配枚举

match的语法大致如下

match 变量{
结果1 => 表达式1,
结果2 => 表达式2,
_ => 剩余结果处理
}

enum NeuralNetwork {CNN(String),RNN(String),GAN(String)
}fn main(){let nn1 = NeuralNetwork::CNN(String::from("TextCNN"));match nn1 {NeuralNetwork::CNN(s) => println!("CNN 变体为 {}", s), //匹配到对应类型,后面写表达式,而括号内的s就是枚举所绑定类型NeuralNetwork::RNN(s) => println!("RNN 变体为 {}", s),NeuralNetwork::GAN(s) => println!("GAN 变体为 {}", s)}
}

需要注意的是match需要把每一种结果都列出来,如果剩下的不想列可以使用通配符_来表示.

enum NeuralNetwork {CNN(String),RNN(String),GAN(String)
}fn main(){let nn1 = NeuralNetwork::CNN(String::from("TextCNN"));match nn1 {NeuralNetwork::CNN(s) => println!("CNN 变体为 {}", s),_ => println!("非CNN") //剩余类型统一处理}
}

如果箭头后面需要处理更复杂的逻辑,则可以用函数块来写,如下

enum NeuralNetwork {CNN(String),RNN(String),GAN(String)
}fn main(){let nn1 = NeuralNetwork::CNN(String::from("TextCNN"));match nn1 {NeuralNetwork::CNN(s) => {let len = s.len();println!("CNN 变体为 {} {}", s, len);},_ => println!("非CNN");}
}

除此之外match其实是有返回值的,正如函数块的最后一个运算式为返回值一样,match的返回值为=>后的值

enum NeuralNetwork {CNN(String),RNN(String),GAN(String)
}fn main(){let nn1 = NeuralNetwork::CNN(String::from("TextCNN"));let res = match nn1 {NeuralNetwork::CNN(s) => {println!("CNN 变体为 {}", s);s //s是返回值,返回给res,下面同理},NeuralNetwork::RNN(s) => {println!("RNN 变体为 {}", s);s},NeuralNetwork::GAN(s) => {println!("GAN 变体为 {}", s);s}};println!("res is {}", res)
}

除了枚举之外,match也可以匹配别的值

fn main(){let x = 10;match x {1 => println!("Is one!"),2 => println!("Is tow"),_ => println!("Other number!")};
}
fn main(){let x = "adasdasd";match x {"abc" => println!("Is abc!"),"efg" => println!("Is efg"),_ => println!("Other string!")};
}

if let语句

如果指向match一种情况,则可以使用if let这个语法糖,只针对一种模式进行匹配

enum NeuralNetwork {CNN(String),RNN(String),GAN(String)
}fn main(){let nn1 = NeuralNetwork::CNN(String::from("TextCNN"));if let nn1 = NeuralNetwork::CNN{println!("是CNN");}
}

注意,if let后面的判断是=,而不是==。如果想要处理剩余情况,可以再加一个else

enum NeuralNetwork {CNN(String),RNN(String),GAN(String)
}fn main(){let nn1 = NeuralNetwork::CNN(String::from("TextCNN"));if let nn1 = NeuralNetwork::CNN{println!("是CNN");}else{println!("不是CNN");}
}

Option

Option是一种枚举,包含两种类型,分别是Some和None。Rust设计Option就是为了避免None和其它的值做运算而造成一系列错误而设计的。
Option的定义大致如下:

pub enum Option<T> {None,Some(T),
}

Option可以如下使用

fn main(){let x = Option::Some("hello");let y: Option<&str>= Option::None; //这里属于泛型,需要指定Option的泛型类型let z = x + y; // None无法和y运算,从而保证了安全性
}
fn main(){let _x = Option::Some("hello");let y: Option<&str> = None;match y {Option::None => println!("空的"),Option::Some(t) => println!("非空, 是{}", t)}
}

match pattern

基本pattern

match允许更为复杂的匹配,这称之为匹配的pattern,其中常用的操作如下:

  1. | 用于分割多个可能,Rust会从左到右依次检查是否符合

例如:a | b | c则会 检查a后检查b,再检查是否符合c

  1. ()元组用于实现匹配坐标这类的多个参数数据
  2. 可以用…=b, a…=b这种Range来进行范围的匹配

注意,a…b是左闭右开类型,而加上等号则是左闭右闭

  1. _可以用来匹配剩余未匹配的所有值
fn main(){let x: i32 = 100;match x {1 | 2 | 3 => println!("x位于1到3之间"), //会依次检查x是1,2还是3.只要匹配一个就进入后面的语句4 ..=9 => println!("x位于4到9之间"),10 | 100..=1000 => println!("x为10,或者100-1000之间的数"),_ => println!("x不是所期待的数字")};
}
fn main(){let x: (i32, i32) = (-9, -10);match x {(1, 1) => println!("点(1, 1)"),(1, 2 | 3 | 4) => println!("点(1,2), (1,3)或((1,4))"),(..=-1, ..=-1) => println!("第三象限的点"),_ => println!("其他区域的点")};
}

可以使用@符号把必要时的某个值绑定到变量上,操作为 变量 @ 匹配式

fn main(){let x: (i32, i32) = (-9, -10);match x {(1, 1) => println!("点(1, 1)"),(1, 2 | 3 | 4) => println!("点(1,2), (1,3)或((1,4))"),(x @ ..=-1, y @ ..=-1) => println!("第三象限的点({}, {})", x, y), //绑定第一个空的值到x,同理绑定y。_ => println!("其他区域的点")};
}

pattern守卫

pattern后面可以加上if判断语句来进一步的判断这个匹配是否合法,示例如下

fn judge_prime(x: i32) -> bool{// TODO: 判断素数true
}
fn main(){let tmp: (i32, i32) = (-9, -10);match tmp {(x @ 0..=10, y @ _) if x == y => println!("在y=x直线上(0 <= x <= 100)"),(x @ 0..=100, y @ 0..=100) if judge_prime(x) && judge_prime(y) => println!("(x, y)为0-100内的素数坐标"),_ => println!("")};
}

当然if后面的语句可以替换成函数块{}只要其返回值是bool类型即可。

fn judge_prime(_x: i32) -> bool{// TODO: 判断素数true
}fn main(){let tmp: (i32, i32) = (-9, -10);match tmp {(x, y) if x == y => println!("在y=x直线上"), //此时x,y无绑定,也就是无绑定上的约束(x @ 0..=100, y @ 0..=100) if {let tmp: bool = judge_prime(x);tmp && judge_prime(y)}=> println!("(x, y)为0-100内的素数坐标"),_ => println!("")};
}

泛型

如其他语言(CPP,JAVA)一样,Rust也支持泛型。

泛型函数

泛型函数需要在函数名上指明泛型类型,通常用T,U这种大写字母来表示

fn qpow<T>(base: T, p: i32) -> T{//TODO实现快速幂的逻辑
}

上述函数中T表示某个抽象的类型,而这个类型需要在函数名部分标注出来。随后的base和返回值都是T类型。
当然涉及到两个或者多个翻新类型时,需要都在函数名后面声明出

fn Test<T, U>(x: T, y: U) -> (T, U){//TODO
}

泛型结构体

与函数类似,可以在结构体明上声明某个或者多个抽象类型

struct Point<T>{x: T,y: T
}
fn main(){let ip = Point{x: 10, y: 10}; //此时ip类型为Point<i32>let fp = Point{x: 10.0, y: 11.1};//此时ip类型为Point<f64>
}

注意,Rust在编译时会把所有的抽象类型T替换成具体的类型,因为Rust是静态的,所以在编译之后所有的抽象类型都已经有具体的确定类型的值了。

struct Point<T>{x: T,y: T
}
fn main(){let ip: Point<i64> = Point{x: 10, y: 10}; //强制约束为i64let fp = Point{x: 10.0, y: 11};//报错,因为有两个类型
}

泛型枚举

枚举的泛型就是把其变体所绑定的类型内添加泛型,前面的Option的Some就是这个原理。

enum Test<T, U> {SOME(T, U),OTHER(T),NO

为结构体绑定泛型方法

为结构体绑定方法使用impl关键字,如果该结构体是一个泛型结构体,则需要再impl后面加表明抽象类型。

struct Point<T>{x: T,y: T    
}impl Point<i32> { //只为i32类型实现判断素数坐标的方法, 由于是实现具体类型所以不需要再impl后面加尖括号fn judge_prime(&self) -> bool{//TODO判断素数}
}impl<T> Point<T> { //为所有类型都实现一个画图的方法,抽象方法要加尖括号表明抽象类型fn show_point(&self) -> (){//TODO画图}
}

注意,此时impl的泛型参数不影响具体方法的参数

struct Point<T, U>{x: T,y: U
}impl<T, U> Point<T, U> {fn make_new_point<W>(&self, other_point: Point<T, W>) -> Point<T, W>{Point { x: self.x.clone(),  //这里会有报错,具体原因看后面的trait部分y: other_point.y }}
}fn main(){
}

trait

trait的定义与实现

trait是Rust的一个类似于接口的类型,他可以为enum,struct来定义一套标准的接口,或者默认的某些方法。

trait 名字{
函数|抽象函数
}

看下面的例子

trait Draw {fn _draw_atom(&self) ->(); //实现单个点的绘画,是一个抽象的方法fn draw(&self) -> (){ //draw绘画调用_draw_atom,是一个已经实现的方法self._draw_atom()}
}

使用

impl trait类型 for 结构体|枚举

来为结构体或者枚举绑定方法

struct Point{x: f64,y: f64
}struct Line{A: f64,B: f64
}trait Draw {fn _draw_atom(&self) ->();fn draw(&self) -> (){ //该方法为所有实现Draw trait的结构体/枚举所共有self._draw_atom()}
}impl Draw for Point { //为Point结构体实现fn _draw_atom(&self) ->() {println!("{} {}", self.x, self.y);}
}impl Draw for Line {//为Line结构体实现fn _draw_atom(&self) -> (){println!("{}x + {}y = 0", self.A, self.B);}
}

用trait指定定特定方法

首先对于简单的约束,我们可以直接在函数参数后面加上 impl trait类型 的方式来要求某个参数必须实现特定的trait

fn Test(x: impl Draw){ //约束x必须实现Draw
}

如果类型比较多,且复杂则可以使用Bound的方式具体做法如下

在函数名后面用尖括号,写上泛型,然后后面用冒号指定trait
函数名<T: trait1 + traiit2+…, U: trait1+traitk…>

use std::fmt::Display; //使用fmt内的Display trait
fn Test<T: Draw + Display, U: Display>(x: T, y: U){} 
//要求x实现了Draw和Display两个trait,而y只要求实现Display这个trait

此时你会发现bound约束太长了,降低了函数的可读性。于是Rust允许使用where关键字把Bound约束后置, 具体做法如下

  1. 在函数尖括号后声明泛型,T,U等变量。
  2. 在函数的函数体前用where关键字,后面跟上每个泛型变量的约束trait
use std::fmt::Display;
fn Test<T, U>(x: T, y: U)
whereT: Draw + Display, //约束TU: Display //约束U
{//TODO:函数体
} 

我们同样可以再返回类型上约束实现具体的trait。但此时需要注意,返回的类型必须要是一种类型,不能使用分支语句使其返回多种可能的类型

use std::fmt::Display;
fn Test<T, U>(x: T, y: U) -> U //返回类型必须实现了Display
whereT: Draw + Display, //约束TU: Display //约束U
{//TODO:函数体
} 

impl中的trait约束

除此之外,在impl中的泛型T,也可以进行相对应的trait的约束

impl<T: Display> Point<T>{ 
//对所有实现了Display trait的类型T,其Point<T>都会具有test方法fn test(&self){}}

trait可以进行覆盖实现,也就是为所有实现某些trait的类型添加一些方法


trait Hello {fn print_hello(){println!("hello");}
}impl<T: std::fmt::Display> Hello for T{//为所有实现了Display这个trait的类型都添加一个print_hello函数}
fn main(){i32::print_hello(); //此时实现了Display的i32类型,也可以调用这个方法了
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/40823.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录算法训练营二刷第一天| 704. 二分查找,27. 移除元素

代码随想录算法训练营二刷第一天| 704. 二分查找&#xff0c;27. 移除元素 文章目录 代码随想录算法训练营二刷第一天| 704. 二分查找&#xff0c;27. 移除元素一、704. 二分查找二、35.搜索插入位置三、34. 在排序数组中查找元素的第一个和最后一个位置四、69.x 的平方根五、3…

【回溯】总结

1、 组合和子集问题 组合问题需要满足一定要求才算作一个答案&#xff0c;比如数量要求&#xff08;k个数&#xff09;&#xff0c;累加和要求&#xff08;target&#xff09;。 子集问题是只要构成一个新的子集就算作一个答案。 进阶&#xff1a;去重逻辑。 一般都是要对同…

Linux 5种网络IO模型

Linux IO模型 网络IO的本质是socket的读取&#xff0c;socket在linux系统被抽象为流&#xff0c;IO可以理解为对流的操作。刚才说了&#xff0c;对于一次IO访问&#xff08;以read举例&#xff09;&#xff0c;数据会先被拷贝到操作系统内核的缓冲区中&#xff0c;然后才会从操…

LL库实现SPI MDA发送方式驱动WS2812

1&#xff0c;首先打卡STM32CubeMX&#xff0c;配置一下工程&#xff0c;这里使用的芯片是STM32F030F4P6。 时钟 SPI外设 SPI DMA 下载接口&#xff0c;这个不配置待会下程序后第二次就不好下载调试了。 工程配置&#xff0c;没啥说的 选择生成所有文件 将驱动都改为LL库 然后直…

OpenCV之特征点匹配

特征点选取 特征点探测方法有goodFeaturesToTrack(),cornerHarris()和SURF()。一般使用goodFeaturesToTrack()就能获得很好的特征点。goodFeaturesToTrack()定义&#xff1a; void goodFeaturesToTrack( InputArray image, OutputArray corners,int maxCorners, double qualit…

jmeter errstr :“unsupported field type for multipart.FileHeader“

在使用jmeter测试接口的时候&#xff0c;提示errstr :"unsupported field type for multipart.FileHeader"如图所示 这是因为我们 在HTTP信息头管理加content-type参数有问题 直接在HTTP请求中&#xff0c;勾选&#xff1a; use multipart/form-data for POST【中文…

22、touchGFX学习Model-View-Presenter设计模式

touchGFX采用MVP架构&#xff0c;如下所示&#xff1a; 本文界面如下所示&#xff1a; 本文将实现两个操作&#xff1a; 1、触摸屏点击开关按键实现打印开关显示信息&#xff0c;模拟开关灯效果 2、板载案按键控制触摸屏LED灯的显示和隐藏 一、触摸屏点击开关按键实现打印开…

Go语言之依赖管理

go module go module是Go1.11版本之后官方推出的版本管理工具&#xff0c;并且从Go1.13版本开始&#xff0c;go module将是Go语言默认的依赖管理工具。 GO111MODULE 要启用go module支持首先要设置环境变量GO111MODULE 通过它可以开启或关闭模块支持&#xff0c;它有三个可选…

docker搭建LNMP

docker安装 略 下载镜像 nginx:最新版php-fpm:根据自己需求而定mysql:根据自己需求定 以下是我搭建LNMP使用的镜像版本 rootVM-12-16-ubuntu:/docker/lnmp/php/etc# docker images REPOSITORY TAG IMAGE ID CREATED SIZE mysql 8.0…

Linux的基本权限(文件,目录)

文章目录 前言一、Linux权限的概念二、Linux权限管理 1.文件访问者分类2.文件类型和访问类型3.文件访问权限的相关设置方法三、目录的权限四、权限的总结 前言 Linux下一切皆文件&#xff0c;指令的本质就是可执行文件&#xff0c;直接安装到了系统的某种路径下 一、Linux权限的…

embed mongodb 集成spring

在property文件下添加 de.flapdoodle.mongodb.embedded.version5.0.5 spring.mongodb.embedded.storage.oplog-size0不指定数据库&#xff0c;会使用test&#xff0c; port默认是0&#xff0c;随机端口号。 oplog-size mac默认是192mb, 其他系统会使用5%的磁盘可用空间&#x…

SpringCloud实用篇6——elasticsearch搜索功能

目录 1 DSL查询文档1.1 DSL查询分类1.2 全文检索查询1.2.1 使用场景1.2.2 基本语法1.2.3 示例1.2.4 总结 1.3 精准查询1.3.1 term查询1.3.2 range查询1.3.3 总结 1.4.地理坐标查询1.4.1 矩形范围查询1.4.2 附近查询 1.5 复合查询1.5.1 相关性算分1.5.2 算分函数查询1&#xff0…

Python 字节码指令 LOAD_DEREF

LOAD_DEREF 是 Python 字节码指令&#xff0c;它与闭包和嵌套函数有关。要理解 LOAD_DEREF&#xff0c;我们首先需要了解 Python 中的几个概念&#xff1a;cell、free variable 和闭包。 Cell 和 Free Variables: 当一个嵌套函数引用了其上级作用域中的一个变量&#xff0c;但该…

【大数据Hive】hive 事务表使用详解

目录 一、前言 二、Hive事务背景知识 hive事务实现原理 hive事务原理之 —— delta文件夹命名格式 _orc_acid_version 说明 bucket_00000 合并器(Compactor) 二、Hive事务使用限制 参数设置 客户端参数设置 客户端参数设置 三、Hive事务使用操作演示 操作步骤 客…

(已解决)redis.get报错com.alibaba.fastjson.JSONException: autoType is not support

redis存取值问题&#xff0c;存自定义实体对象&#xff1b; 第一次取的时候报错&#xff1a;com.alibaba.fastjson.JSONException: autoType is not support。 GenericFastJsonRedisSerializer序列化和反序列化redis的value值&#xff0c;需要bean对象含有无参构造方法。 解决…

【C语言】回调函数,qsort排序函数的使用和自己实现,超详解

文章目录 前言一、回调函数是什么二、回调函数的使用1.使用标准库中的qsort函数2.利用qsort函数对结构体数组进行排序 三、实现qsort函数总结 先记录一下访问量突破2000啦&#xff0c;谢谢大家支持&#xff01;&#xff01;&#xff01; 这里是上期指针进阶链接&#xff0c;方便…

金融术语总结

洗钱 将犯罪或其他非法违法行为所获得的违法收入&#xff0c;通过各种手段掩饰、隐瞒、转化&#xff0c;使其在形式上合法化的行为。 存量客户 某个时间段里原先已有的客户,与新增客户相对应。 月活跃用户数量&#xff0c;MAU&#xff08;Monthly Active User&#xff0c;M…

【go语言基础】go中的方法

先思考一个问题&#xff0c;什么是方法&#xff0c;什么是函数&#xff1f; 方法是从属于某个结构体或者非结构体的。在func这个关键字和方法名中间加了一个特殊的接收器类型&#xff0c;这个接收器可以是结构体类型的或者是非结构体类型的。从属的结构体获取该方法。 函数则…

【100天精通python】Day37:GUI界面编程_PyQT从入门到实战(上)

目录 专栏导读 1 PyQt6 简介&#xff1a; 1.1 安装 PyQt6 和相关工具&#xff1a; 1.2 PyQt6 基础知识&#xff1a; 1.2.1 Qt 的基本概念和组件&#xff1a; 1.2.2 创建和使用 Qt 窗口、标签、按钮等基本组件 1.2.3 布局管理器&#xff1a;垂直布局、水平布局、网格布局…