Rust语言教程 - if let表达式与枚举进阶

Posted Jtag特工

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Rust语言教程 - if let表达式与枚举进阶相关的知识,希望对你有一定的参考价值。

Rust语言教程(9) - if let表达式与枚举进阶

枚举复习

前面我们介绍了Rust中的枚举类型,以及通过枚举实现的Option, Result等类型。
温故而知新,我们再来复习一下枚举的定义和使用。

首先,Rust的enum可以像C语言中的enum一样,定义一组可枚举的常量值。比如我们可以这样描述带符号的整数:

enum Integers
    Int8,
    Int16,
    Int32,
    Int64,
    Int128,
    Bigint

我们在使用时可以将常量转换为整数来使用,例如:

    let int1 = Integers::Int8;
    println!("",(int1 as i32));

如同C语言一样,Rust的enum常量也可以指定值:

enum Integers
    Int8=1,
    Int16,
    Int32,
    Int64,
    Int128,
    Bigint

除了可以定义常量枚举,Rust还可以定义带有变量的枚举。例如,我们想描述一个8位的整数,它可以是有符号的,也可以是无符号的,我们可以这样定义:

enum Bits8 
    Uint8(u8),
    Int8(i8)

我们就可以用这个Bits8枚举用来既能表示有符号的8位整数,也可以表示无符号的8位整数。为了共享,我们再加上前一节学的Box包装一下:

    let bit1 = Box::new(Bits8::Uint8(1u8));
    let bit2 = Box::new(Bits8::Int8(-2i8));

对于枚举的变量,我们可以通过match模式匹配的方法来对其进行计算。例如:

    match *bit1 
        Bits8::Uint8(value) => println!("unsinged int:",value),
        Bits8::Int8(value) => println!("signed int:",value)
    

当然,针对不匹配的情况,也可以什么也不错。这时候可以使用"_"来匹配不想处理的所有情况:

    match *bit2 
        Bits8::Int8(value) => println!("signed int:",value),
        _ => 
    

if let表达式

因为match表达式要符合MECE原则,所以必须要处理所有的情况。为了代码写起来方便,像Rust和Swift这样的现代语言都实现了if let表达式。
以上面的例子为例,我们的if let表达式可以写为:

    if let Bits8::Uint8(value) = *bit1 
        println!("unsinged int:",value);
    

if let表达式当然也支持else:

        if let Bits8::Uint8(value) = *bit1 
            println!("unsinged int:",value);
         else 
            println!("not unsinged int");
        

我们将bit1改成bit2,就会走else分支。

if let表达式最常用的情况就是在Option或者Result中使用。

比如我们将一个整数放到Option中,然后打包到Box里面:

let num1 = Box::new(Some(1i32));

如果要用到包装的值,暴力的作法是直接unwrap:

let num2 = num1.unwrap() + 1i32;

但是这样的话,如果num1是None的话,就会panic。所以我们可以用if let来判断一下:

    if let Some(num3) = *num1 
        let num4 = num3 + 2i32;
        println!("  ",num2,num3,num4);
    

我们再看一个例子,将Option转化为Result:

fn test(i:Option<Box<i32>>) -> Result<Box<i32>, &'static str>
    match i
        Some(i) => Ok(i),
        None => Err("NAN")
    

为枚举定义方法

以前面的Integers为例,我们不想将类型常量转换为整数来使用,而是想直接使用它们。这时我们可以为枚举定义方法,就像给struct定义方法一样,仍然使用impl关键字来实现。比如我们可以实现Display方法,来让它们可以直接打印:

impl Display for Integers
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result 
        write!(f, ":?", (*self as i32))
    

针对带变量值的枚举类型,为其定义函数的作用将更大。

比如我们前面定义的统一的8位有符号和无符号整数的枚举值,我们现在就可以为其定义算数运算了。

impl Add for Bits8
    type Output = Self;
    fn add(self, other: Self) -> Self::Output 
        match (self, other) 
            (Bits8::Uint8(a), Bits8::Uint8(b)) => Bits8::Uint8(a + b),
            (Bits8::Int8(a), Bits8::Int8(b)) => Bits8::Int8(a + b),
            (Bits8::Uint8(a), Bits8::Int8(b)) => Bits8::Int8(a as i8 + b),
            (Bits8::Int8(a), Bits8::Uint8(b)) => Bits8::Int8(a + b as i8),
        
    

Add是对应“+”的trait,我们可以为Bits8实现Add,然后就可以直接使用“+”了。

    let bit4 = Box::new(Bits8::Uint8(1));
    let bit5 = Box::new(Bits8::Int8(-1));
    let bit6 = *bit4 + *bit5;
    println!("bit6:",bit6);

我们还可以使用上节学习的Arc将枚举值封装到多线程共享的变量中,这时在进行加法之前我们先将其borrow出来:

    let bit4 = Arc::new(Bits8::Uint8(1));
    let bit5 = Arc::new(Bits8::Int8(-1));
    let b4: &Bits8= bit4.borrow();
    let b5: &Bits8= bit5.borrow();
    let b6 = b4 + b5;
    println!("Arc::?",b6);

borrow出来的结果是引用,没法使用上面针对于Bits8的Add方法,所以我们需要再定义一个Add方法,针对于引用。
返回值的时候我们就不要返回引用了,将其分配到Arc中再返回:

impl Add for &Bits8
    type Output = Arc<Bits8>;
    fn add(self, other: Self) -> Self::Output 
        match (self, other) 
            (Bits8::Uint8(a), Bits8::Uint8(b)) => Arc::new(Bits8::Uint8(a + b)),
            (Bits8::Int8(a), Bits8::Int8(b)) => Arc::new(Bits8::Int8(a + b)),
            (Bits8::Uint8(a), Bits8::Int8(b)) => Arc::new(Bits8::Int8((*a) as i8 + b)),
            (Bits8::Int8(a), Bits8::Uint8(b)) => Arc::new(Bits8::Int8(a + (*b) as i8)),
        
    

小结

Rust的枚举是可以定义方法的,这样会大大有助于我们像使用struct一样使用枚举。
另外,if let也是非常有用的,可以让我们在不使用match的情况下,对枚举值进行判断和处理,可以大大简化代码,提升编程效率。
同样,也有while let这样的语法糖。

以上是关于Rust语言教程 - if let表达式与枚举进阶的主要内容,如果未能解决你的问题,请参考以下文章

Rust语言教程 - if let表达式与枚举进阶

Rust语言教程 - if let表达式与枚举进阶

Rust学习教程20 - match和if let

Rust学习教程20 - match和if let

Rust语言圣经20 - match和if let

Rust学习教程17 - 枚举enum