文章目录
enum枚举
fn test04_match() {
// 定义一个枚举类型
enum Gender {
Male = 1,
Female = 2,
}
//枚举类型占用的字节数,取决于其中“最宽”(占用字节数最大)的成员
// 如果修改Gender定义中Female=2000,那么Gender
// 类型将会占用2个字节
println!("size: {}", std::mem::size_of::<Gender>());//1
match模式匹配
fn gender_str(g: Gender) -> String {
// match是rust中用于模式匹配的关键字
match g {
Gender::Male => "Male".to_owned(),
Gender::Female => "Female".to_owned(),
}
}
println!("{:?}", gender_str(Gender::Male));//"Male"
println!("{:?}", gender_str(Gender::Female));//"Female"
}
带条件(guard)的模式匹配
let fraction = (10, 20);
// 带条件判断(guard)的match
// if y!=0
match fraction {
(x, y) if y!=0 => {
println!("{x}/{y}") //10/20
}
_ => ()
}
open range模式匹配
// 1.55版本新增的open range pattern
let score: usize = 60;
let score_desc:&str = match score {
0..=59 => "D",
60..=74 => "C",
75..=89 => "B",
90..=100 => "A",
_ => unreachable!(),
};
println!("score: {}, score_desc:{}", score, score_desc);
Option< T >和带参数的模式匹配
先来看看标准库中Option<T>
的定义:
pub enum Option<T> {
/// No value
None,
/// Some value `T`
Some(T),
}
这是一个带泛型参数T的枚举,代表一个T类型的值,或者None。
let x: Option<i32> = None;
let y: Option<i32> = Some(100);
println!("{:?}", x);//None
println!("{:?}", y);//Some(100)
// 带参数的模式匹配
if let Some(xval) = y {
println!("Some(x={})", xval);//Some(x=100)
}
unwrap()和expect()
unwrap()
和expect()
内部通过match模式匹配
将Option/Resut
中的值取出来,如果没有值,会panic!
。
其中,expect()
支持传入一个自定义的panic
文本信息。
let v = y.unwrap();
let v2 = x.expect("Some error happened");
其中unwrap函数
的定义为:
pub const fn unwrap(self) -> T {
match self {
Some(val) => val,
None => panic!("called `Option::unwrap()` on a `None` value"),
}
}
仿写自己的MyOption
接下来,我们尝试仿写一个自己的MyOption<T>
:
enum MyOption<T> {
None,
Some(T),
}
let x: MyOption<i32> = MyOption::None;
let y = MyOption::Some(100);
// println!("{:?}", x);
// println!("{:?}", y);
如果忽略到被注释的println!
,看起来还是很OK的。但是一旦尝试打印x
和y
,编译器就会报错
MyOption<{integer}>
doesn’t implementDebug
报MyOption类型没有实现Debug trait
给MyOption< T >实现Debug trait
接下来,就给MyOption<T>
类型,增加Debug trait
的实现:
// use用来引入一个类型
use std::fmt::Debug;
use std::fmt::Result;
// 要求泛型参数T也必须实现了Debug
impl<T: Debug> Debug for MyOption<T>
{
// 实现Debug trait中的fmt方法
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result {
match self {
// 往f中写入"None"
Self::None => write!(f, "None"),
// 也是带参数的模式匹配
Self::Some(arg) => f.debug_tuple("Some").field(arg).finish(),
}
}
}
Result< T , E >
标准库中的Result<T,E>也是带泛型参数的枚举,代表一个“成功”意义下的结果T,或者一个“失败”意义下的结果E。
enum Result<T, E> {
/// Contains the success value
Ok(T),
/// Contains the error value
Err(E),
}
//认识Resut<T,E>
let x: Result<i32, i32> = Ok(0);
let y: Result<i32, i32> = Err(99);
println!("{:?}", x);
println!("{:?}", y);
let x1 = x.unwrap();
let y1 = y.expect("Is Err");
map_or/map_or_else
先来看看Option<T>
中map_or
函数的定义:
pub fn map_or<U, F: FnOnce(T) -> U>(self, default: U, f: F) -> U {
match self {
Some(t) => f(t),
None => default,
}
}
其中U和F是两个泛型参数,F是带一个T类型输入参数,返回U类型的FnOnce函数/闭包。map_or最终返回的是U类型。
可以看到,map_or
内部封装了一个match匹配
,是为了方便提取Option中的值而存在的:
- 如果本身是None,直接返回传给map_or的第一个参数(这里姑且把self当做第0个参数吧)作为最终的返回值。
- 如果本身是Some(t),那么函数调用结果
f(t)
将会被作为最终的返回值。
我们通过定义如下一个is_even
函数来熟悉map_or
的用法:
// 对于一个x类型的Option<i32>,如果x是None,直接返回map_or的第一个参数值(false),
// 如果x中的i32值是偶数返回true,是奇数返回false。
fn is_even(x: Option<i32>) -> bool {
x.map_or(false, |x|x%2==0)
}
println!("{}", is_even(None));//false
println!("{}", is_even(Some(1)));//false
println!("{}", is_even(Some(2)));//true
map_or_else
跟map_or
不同的是,第一个参数也是FnOnce函数,在match遇到None时,会调用此函数,而不是直接返回一个默认值。
fn my_unwrap(x: Option<u8>) -> i32 {
x.map_or_else(||-1, |x|x as i32)
}
println!("{}", my_unwrap(None));//-1
println!("{}", my_unwrap(Some(1)));//1
println!("{}", my_unwrap(Some(2)));//2
实战,定义一个函数,判断一个列表中的数是否是递增的(要求用map_or来实现):
fn is_ascending(x: &Vec<i32>) -> bool {
let mut iter = x.iter();
// 对迭代器中的第一个元素进行map_or
iter.next().map_or(true, |mut prev| {
// 遍历迭代器中除第一个元素外,其余的元素
for cur in iter {
if cur >= prev {
prev = cur;
} else {
return false;
}
}
true
})
}
println!("{}", is_ascending(&vec![]));//true
println!("{}", is_ascending(&vec![1,2,5]));//true
println!("{}", is_ascending(&vec![9,2,5]));//false
Result<T,E>
中的map_or/map_or_else
也是同样的用法。不同之处,仅仅在于Option<T>
中用于匹配None
的情况,在Result<T,E>
中被换成了Err(e)
。