rust枚举

一、定义枚举

1.使用enum关键字定义枚举。
语法格式如下

enum enum_name {variant1,variant2,variant3
}

例如

enum Fruits {Banana, // 香蕉Pear, // 梨Mandarin, // 橘子Eggplant // 茄子
}

2.可以为枚举成员添加属性

enum Book {Papery(u32),Electronic(String),
}
let book = Book::Papery(1001);
let ebook = Book::Electronic(String::from("url://..."));

如果你想为属性命名,可以用结构体语法:

enum Book {Papery { index: u32 },Electronic { url: String },
}
let book = Book::Papery{index: 1001};

二、使用枚举

(一)使用::
语法格式如下

enum_name::variant

例如

let selected = Fruits::Banana;
let selected: Fruits = Fruits::Banana;

范例

#[derive(Debug)]
enum Fruits {Banana, // 香蕉Pear, // 梨Mandarin, // 橘子Eggplant // 茄子
}
fn main() {let selected = Fruits::Banana;println!("{:?}",selected);
}
编译运行结果如下
Banana

(二)判断枚举
只能使用match语句判断枚举

enum CarType {Hatch,Sedan,SUV
}
fn print_size(car:CarType) {match car {CarType::Hatch => {println!("Small sized car");},CarType::Sedan => {println!("medium sized car");},CarType::SUV =>{println!("Large sized Sports Utility car");}}
}
fn main(){print_size(CarType::SUV);print_size(CarType::Hatch);print_size(CarType::Sedan);
}
编译运行结果如下
Large sized Sports Utility car
Small sized car
medium sized car

带属性的枚举

#[derive(Debug)]
enum GenderCategory {Name(String),Usr_ID(i32)
}
fn main() {let p1 = GenderCategory::Name(String::from("Mohtashim"));let p2 = GenderCategory::Usr_ID(100);println!("{:?}",p1);println!("{:?}",p2);match p1 {GenderCategory::Name(val)=> {println!("{}",val);}GenderCategory::Usr_ID(val)=> {println!("{}",val);}}
}
编译运行结果如下
Name("Mohtashim")
Usr_ID(100)
Mohtashim

三、标准库枚举

标准库内置了很多枚举

(一)Option
这个枚举是Option<T>,而且它定义于标准库中,如下:

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

它有两个枚举值 None 和 Some(T)。
None 表示可有可无中的无。
Some(T) 表示可有可无中的有,既然有,那么就一定有值,那个T就表示值的类型。

1.定义枚举值
Option<T> 枚举包含在了prelude之中,你不需要将其显式引入作用域。另外,它的成员也是如此,可以直接使用Some和None,不需要加Option:: 前缀。

定义枚举值,可以使用Some(value)或者None。
例子:

let some_number = Some(5);
let some_string = Some("a string");
let absent_number: Option<i32> = None;

如果使用None,需要指定Option<T> 是什么类型的,因为编译器只通过None无法推断出Some成员的类型。

当有一个Some值时,我们就知道存在一个值,而这个值保存在Some中。当有个None值时,在某种意义上,它跟空值具有相同的意义:并没有一个有效的值。
那么,Option<T> 为什么就比空值要好呢?
当在Rust中拥有一个像i8这样类型的值时,编译器确保它总是有一个有效的值。我们可以自信使用而无需做空值检查。只有当使用Option<i8>的时候需要担心可能没有值,而编译器会确保我们在使用值之前处理了为空的情况。
换句话说,在对Option<T> 进行T的运算之前必须将其转换为T。通常这能帮助我们捕获到空值最常见的问题之一:假设某值不为空但实际上为空的情况。
不再担心会错误地假设一个非空值,会让你对代码更加有信心。为了拥有一个可能为空的值,你必须要显式地将其放入对应类型的Option<T> 中。接着,当使用这个值时,必须明确地处理值为空的情况。只要一个值不是Option<T> 类型,你就 可以 安全地认定它的值不为空。这是Rust的一个经过深思熟虑的设计决策,来限制空值的泛滥以增加Rust代码的安全性。

2.使用枚举
(1)获取some的值
expect
如果是Some,就返回Some的值。如果是None就打印消息,并崩溃。
Panics
如果值为 None 并带有由 msg 提供的自定义panic消息,就会出现panics。
例子

let x = Some("value");
assert_eq!(x.expect("fruits are healthy"), "value");let x: Option<&str> = None;
x.expect("fruits are healthy"); // `fruits are healthy` 的panics

unwrap
如果是Some,就返回Some的值。如果是None就崩溃。
由于此函数可能会panic,因此通常不建议使用该函数。 应该使用match显式处理None,或者调用unwrap_or,unwrap_or_else,unwrap_or_default。
Panics
如果self的值等于 None,就会出现panics。
例子

let x = Some("air");
assert_eq!(x.unwrap(), "air");
let x: Option<&str> = None;
assert_eq!(x.unwrap(), "air"); //崩溃

unwrap与expect一样,唯一不同是expect能打印自定义消息,而unwrap不能

(2)判断是否有值
is_some
如果选项是 Some 值,则返回 true。
例子

let x: Option<u32> = Some(2);
assert_eq!(x.is_some(), true);
let x: Option<u32> = None;
assert_eq!(x.is_some(), false);

is_none
如果选项是 None 值,则返回 true。
例子

let x: Option<u32> = Some(2);
assert_eq!(x.is_none(), false);
let x: Option<u32> = None;
assert_eq!(x.is_none(), true);

(3)逻辑运算
and
如果自己为 None,则返回 None; 否则,返回参数。
例子

let x = Some(2);
let y: Option<&str> = None;
assert_eq!(x.and(y), None);let x: Option<u32> = None;
let y = Some("foo");
assert_eq!(x.and(y), None);let x = Some(2);
let y = Some("foo");
assert_eq!(x.and(y), Some("foo"));let x: Option<u32> = None;
let y: Option<&str> = None;
assert_eq!(x.and(y), None);

or
如果自己有值,则返回自己,否则返回参数。
例子

let x = Some(2);
let y = None;
assert_eq!(x.or(y), Some(2));let x = None;
let y = Some(100);
assert_eq!(x.or(y), Some(100));let x = Some(2);
let y = Some(100);
assert_eq!(x.or(y), Some(2));let x: Option<u32> = None;
let y = None;
assert_eq!(x.or(y), None);

xor
如果自己和参数之一恰好是Some,则返回 Some,否则返回 None。
例子

let x = Some(2);
let y: Option<u32> = None;
assert_eq!(x.xor(y), Some(2));let x: Option<u32> = None;
let y = Some(2);
assert_eq!(x.xor(y), Some(2));let x = Some(2);
let y = Some(2);
assert_eq!(x.xor(y), None);let x: Option<u32> = None;
let y: Option<u32> = None;
assert_eq!(x.xor(y), None);

(二)Result
Option枚举返回 None 可以表明失败。但是有时要强调为什么会失败。为做到这点,我们提供了 Result 枚举类型。

enum Result<T, E> {Ok(T),Err(E),
}

Result<T, E> 有两个取值:
Ok(value) 表示操作成功,并包装操作返回的 value(value 拥有 T 类型)。
Err(why),表示操作失败,并包装 why,它能够解释失败的原因(why 拥有 E 类型)。
与Option枚举一样,Result枚举和其成员也被导入到了prelude中,所以就不需要在match分支中的Ok和Err之前加Result::。

1.定义枚举
使用Ok(value)和Err(why)
例子

let ok = Ok(5);
let err = Err("not a string");

2.使用枚举
(1)获取Ok的值
expect
返回包含 self 值的包含的 Ok 值。
由于此函数可能为panic,因此通常不建议使用该函数。 应该使用match显式处理 Err,或者调用 unwrap_or,unwrap_or_else,unwrap_or_default。
Panics
如果值为 Err,就会出现panics,其中panic消息包括传递的消息以及 Err 的内容。
例子

let x: Result<u32, &str> = Ok(2);
assert_eq!(x.expect("expect a num"), 2);let x: Result<u32, &str> = Err("emergency failure");
x.expect("Testing expect"); // `Testing expect: emergency failure` 的panics

unwrap
返回包含 self 值的包含的 Ok 值。
由于此函数可能为panic,因此通常不建议使用该函数。 应该使用match显式处理Err,或者调用unwrap_or,unwrap_or_else,unwrap_or_default。
Panics
如果该值为 Err,就会出现Panics,并由 Err 的值提供panic消息。
例子

let x: Result<u32, &str> = Ok(2);
assert_eq!(x.unwrap(), 2);let x: Result<u32, &str> = Err("emergency failure");
x.unwrap(); // `emergency failure` 的panics

unwrap_or_else

use std::fs::File;
use std::io::ErrorKind;
fn main() {let f = File::open("hello.txt").unwrap_or_else(|error| {if error.kind() == ErrorKind::NotFound {File::create("hello.txt").unwrap_or_else(|error| {panic!("Problem creating the file: {:?}", error);})} else {panic!("Problem opening the file: {:?}", error);}});
}

(2)判断是否是ok
is_ok
如果结果为 Ok,则返回 true。
例子

let x: Result<i32, &str> = Ok(-3);
assert_eq!(x.is_ok(), true);
let x: Result<i32, &str> = Err("Some error message");
assert_eq!(x.is_ok(), false);

is_err
如果结果为 Err,则返回 true。
例子

let x: Result<i32, &str> = Ok(-3);
assert_eq!(x.is_err(), false);
let x: Result<i32, &str> = Err("Some error message");
assert_eq!(x.is_err(), true);

(3)转换错误
ok
Result<T, E> 转换为 Option<T>
将 self 转换为 Option<T>,使用 self,并丢弃错误 (如果有)。
Examples

let x: Result<u32, &str> = Ok(2);
assert_eq!(x.ok(), Some(2));
let x: Result<u32, &str> = Err("Nothing here");
assert_eq!(x.ok(), None);

err
Result<T, E> 转换为 Option<E>
将 self 转换为 Option<E>,使用 self,并丢弃成功值 (如果有)。
Examples

let x: Result<u32, &str> = Ok(2);
assert_eq!(x.err(), None);
let x: Result<u32, &str> = Err("Nothing here");
assert_eq!(x.err(), Some("Nothing here"));

(4)函数返回错误,称为传播错误
例子

use std::io;
use std::io::Read;
use std::fs::File;
fn read_username_from_file() -> Result<String, io::Error> {let f = File::open("hello.txt");let mut f = match f {Ok(file) => file,Err(e) => return Err(e),};let mut s = String::new();match f.read_to_string(&mut s) {Ok(_) => Ok(s),Err(e) => Err(e),}
}

这种传播错误是如此的常见,以至于Rust提供了 ?运算符来简化操作。
?运算符用在返回值为Result的表达式后面,它等同于这样一个match表达式:其中Err(err)分支展开成return Err(err),而Ok(ok)分支展开成ok。
例子

use std::io;
use std::io::Read;
use std::fs::File;
fn read_username_from_file() -> Result<String, io::Error> {let mut f = File::open("hello.txt")?;let mut s = String::new();f.read_to_string(&mut s)?;Ok(s)
}

可以在 ? 之后直接使用链式方法调用来进一步缩短代码

use std::io;
use std::io::Read;
use std::fs::File;
fn read_username_from_file() -> Result<String, io::Error> {let mut s = String::new();File::open("hello.txt")?.read_to_string(&mut s)?;Ok(s)
}

? 运算符只能用于返回Result的函数
下面代码编译错误

use std::fs::File;
fn main() {let f = File::open("hello.txt")?;
}

有两种方法修复这个问题。一是将函数返回值类型修改为Result<T, E>。二是不使用?运算符。
main函数是特殊的,其返回类型是有限制的。main函数的一个有效的返回值是 (),另一个有效的返回值是Result<T, E>,如下所示:

use std::error::Error;
use std::fs::File;
fn main() -> Result<(), Box<dyn Error>> {let f = File::open("hello.txt")?;Ok(())
}

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

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

相关文章

【CNN-FPGA开源项目解析】卷积层01--floatMult16模块

文章目录 (基础)半精度浮点数的表示和乘运算16位半精度浮点数浮点数的乘运算 floatMult16完整代码floatMult16代码逐步解析符号位sign判断指数exponent计算尾数fraction计算尾数fraction的标准化和舍位整合为最后的16位浮点数结果[sign,exponent,fraction] 其他变量宽度表alway…

系统运维工程师

文章目录 引言I 任职要求II Sentinel2.1 安装2.2 开放防火墙端口:III zipkinsee also引言 云效devops部署解决方案: Java应用构建并部署ECS、K8s、SAE、EDAS。 部署微服务的服务器选择。域名劫持:网站被拦截到特定网址,如何解决。你认为初级运维工程师和高级运维工程师的区…

管理公司和管理工作室

有一段时间在写小游戏&#xff0c;最近unity3d 闹出一则荒唐事情&#xff0c;其实说白一点。老贼就要收费这个事情不会妥协。好不容易做了一次坏人。不过说到这一点我们不得不说管理公司这个事情。unity3d在一些新闻公布有7000多员工&#xff0c;这样看起来似乎是不是有点多了&…

HJ90 合法ip 判断合法字符串

题目链接&#xff1a;https://www.nowcoder.com/practice/995b8a548827494699dc38c3e2a54ee9 IPV4地址可以用一个32位无符号整数来表示&#xff0c;一般用点分方式来显示&#xff0c;点将IP地址分成4个部分&#xff0c;每个部分为8位&#xff0c;表示成一个无符号整数&#xff…

Aspose转pdf乱码问题

一、问题描述 ​ 在centos服务器使用aspose.word转换word文件为pdf的时候显示中文乱码(如图)&#xff0c;但是在win服务器上使用可以正常转换 二、问题原因 由于linux服务器缺少对应的字库导致文件转换出现乱码的 三、解决方式 1.将window中字体(c:\windows\fonts)放到linux…

Spring Authorization Server优化篇:Redis值序列化器添加Jackson Mixin,解决Redis反序列化失败问题

前言 在授权码模式的前后端分离的那篇文章中使用了Redis来保存用户的认证信息&#xff0c;在Redis的配置文件中配置的值序列化器是默认的Jdk序列化器&#xff0c;虽然这样也可以使用&#xff0c;但是在Redis客户端中查看时是乱码的(看起来是)&#xff0c;如果切换为Jackson提供…

leetcode刷题 二维数组 八方向

题目描述 输入&#xff1a;board [[0,1,0],[0,0,1],[1,1,1],[0,0,0]] 输出&#xff1a;[[0,0,0],[1,0,1],[0,1,1],[0,1,0]] 题目分析:就是以二维数组某个元素为中心&#xff0c;寻找周围八个方向的元素&#xff0c;按照题目要求修改二维数组元素返回&#xff1b; 拷贝一份二…

Git 代理(Proxy) 配置

某些情况下,我们需要通过代理才能访问特定网络环境下的git资源,git支持代理配置, 支持 http(s), SOCKS4/SOCKS5. HTTP(S) HTTP 代理配置格式如下: git config --global http.proxy http://[proxy]:[port]实际环境下, 其实我们大多数情况下,并不需要全部git资源都需要通过代理…

ElementUI实现登录注册+axios全局配置+CORS跨域

一、搭建项目 1.1 安装 Element-UI 先确保是否安装了vue-cli脚手架工具 !!! 安装vue脚手架可以看看我的上一篇博客 构建好项目后通过npm安装element-ui cd 项目根路径 #进入新建项目的根目录 npm install element-ui -S #安装…

AUTOSAR 面试知识回顾

如果答不上来&#xff0c;就讲当时做了什么 1. Ethernet基础: 硬件接口&#xff1a; ECU到PHY&#xff1a; data 是MII总线&#xff0c; 寄存器控制是SMI总线【MDCMDIO两根线, half duplex】PHY输出(100BASE-T1)&#xff1a; MDI总线&#xff0c;2 wire 【T1: twisted 1 pair …

C#__简单使用TCP/UDP发送消息

Socket(套接字、插口) TCP和UCP的区别&#xff1a; 1、基于连接和无连接 2、对系统资源的要求&#xff08;TCP较多&#xff0c;UCP少&#xff09; 3、UDP程序结构简单 4、流模式和数据报模式 5、TCP保证数据正确性和数据先后顺…

Java21虚拟线程实践

文章目录 虚拟线程的使用什么是虚拟线程虚拟线程和协程相同之处&#xff1a;不同之处&#xff1a; 总结 就在前几天&#xff0c;java21正式版发布了&#xff0c;作为继java17之后的又一个长期支持版本 (LTS)&#xff0c;为我们带来了很多新的特性&#xff0c;其中我最感兴趣的就…

【线性代数】

0、线性代数的本质往往被淹没在计算的海洋中&#xff0c;无人问津&#xff01; 1、什么是向量&#xff1f; 向量是带方向的箭头&#xff0c;向量是坐标。 2、向量的线性组合 两个向量不共线&#xff0c;即线性无关&#xff1b;两个向量共线&#xff0c;即线性相关。 两个不…

关于地址存放的例题

unsigned int a 0x1234; unsigned char b *(unsigned char*)&a; 上面代码大端存储和小端存储的值分别是多少&#xff1f; 大端存储的是把高位地址存放在低位地址处&#xff0c;低位存放到高位。小端是高位存放在高位&#xff0c;低位在低位。因为a是整型&#xff0c;所…

GraphQL基础知识与Spring for GraphQL使用教程

文章目录 1、数据类型1.1、标量类型1.2. 高级数据类型 基本操作2、Spring for GraphQL实例2.1、项目目录2.2、数据库表2.3、GraphQL的schema.graphql2.4、Java代码 3、运行效果3.1、添加用户3.2、添加日志3.3、查询所有日志3.4、查询指定用户日志3.5、数据订阅 4、总结 GraphQL…

C 语言简单入门

C 语言发展历史|标准 1972年&#xff0c;丹尼斯里奇&#xff08;Dennis Ritch&#xff09;和肯汤普逊&#xff08;Ken Tompson&#xff09;在贝尔实验室开发 UNIX 操作系统时基于 B 语言设计出 C 语言。 1987年&#xff0c;布莱恩柯林汉&#xff08;Brian Kernighan&#xff…

数据库基础理论

什么是数据库&#xff1f; 数据&#xff1a;描述事物的符号记录&#xff0c;可以是数字、文字、图形、图像、声音、语言等&#xff0c;数据有多种形式&#xff0c;他们都是可以经过数字化后存入计算机。 数据库&#xff1a;存储数据的仓库&#xff0c;是长期存放在计算机内、…

世界前沿技术发展报告2023《世界信息技术发展报告》(三)量子信息技术

&#xff08;三&#xff09;量子信息技术 1. 概述2. 量子计算2.1 阿里巴巴达摩院成功研制两比特量子芯片&#xff0c;单比特操控精度超99.97%2.2 加拿大Xanadu公司开发出可编程光量子计算机2.3 美国英伟达公司为经典-量子混合计算推出开发架构2.4 日本国家自然科学研究所开发出…

SpringBoot实战

ISBN: 978-7-115-43314-5 作者&#xff1a;【美】Craig Walls 译者&#xff1a;丁雪丰 页数&#xff1a;209页 阅读时间&#xff1a;2022-12-27 推荐指数&#xff1a;★★★☆☆ 阅读本书还是要有一定的基础的&#xff0c;如果想要入门级还是不行&#xff0c; 建议入门级可以看…

python+nodejs+php+springboot+vue 法律知识分享科普系统平台

在设计过程中&#xff0c;充分保证了系统代码的良好可读性、实用性、易扩展性、通用性、便于后期维护、操作方便以及页面简洁等特点。 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 要想实现法律知…