Rust 04: enum枚举 + match模式匹配 + Option<T> + Result<T,E>+ map_or/map_or_else

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的。但是一旦尝试打印xy,编译器就会报错

MyOption<{integer}> doesn’t implement Debug
报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_elsemap_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)

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值