Rust的模式匹配

我爱海鲸 2024-03-10 14:09:41 rust学习

简介模式

1、模式

模式是Rust中的一种特殊语法,用于匹配复杂和简单类型的结构

将模式与匹配表达式和其他构造结合使用,可以更好地控制程序的控制流

模式由以下元素(的一些组合)组成:

―字面值

-解构的数组、enum、struct和 tuple

―变量

―通配符

-占位符

想要使用模式,需要将其与某个值进行比较:

一如果模式匹配,就可以在代码中使用这个值的相应部分

2、用到模式的地方

match的Arm

match表达式的要求;一详尽(包含所有的可能性)

一个特殊的模式:_(下划线):

-它会匹配任何东西

―不会绑定到变量

一通常用于match的最后一个arm;

   或用于忽略某些值。

条件if let表达式

if let表达式主要是作为一种简短的方式来等价的代替只有一个匹配项的matchif let可选的可以拥有else,包括:

  • else if
  • - else if let
  • 但,if let不会检查穷尽性
fn main() {
    let favorite_color:Option<&str> = None;
    let is_tuesday = false;
    let age:Result<u8,_> = "34".parse();

    if let Some(color) = favorite_color {
        println!("1:{}",color);
    } else if is_tuesday {
        println!("2");
    } else if let Ok(age) = age {
        if age > 30 {
            println!("3:{}",age);
        } else {
            println!("4:{}",age);
        }
    } else {
        println!("5");
    }

}

while let条件循环

只要模式继续满足匹配的条件,那它允许while循环一直运行

fn main() {
    let mut stack = Vec::new();

    stack.push(1);
    stack.push(2);
    stack.push(3);

    while let Some(top) = stack.pop() {
        println!("{}",top);
    }

}

for循环

for循环是Rust中最常见的循环

for循环中,模式就是紧随for关键字后的值

fn main() {
    let v = vec!['a','b','c'];

    for (index,value) in v.iter().enumerate()  {
        println!("{},is at index {}",value,index);
    }   
}

let语句

let 语句也是模式

let PATTERN= EXPRESSION;

fn main() {
    let a = 5;

    let (x,y,z) = (1,2,3);

    // let (q,w) = (1,2,3);
}

函数参数

函数参数也可以是模式

fn foo(x:i32) {
    
}

fn print_coordinates(&(x,y):&(i32,i32)) {
    println!("Current location:({},{})",x,y);
}

fn main() {
    let point = (3,5);
    print_coordinates(&point);
}

可辩驳性:
模式是否会无法匹配

模式的两种形式

模式有两种形式:可辨驳的、无可辩驳的

能匹配任何可能传递的值的模式:无可辩驳的

一例如:let x = 5;

对某些可能的值,无法进行匹配的模式:可辨驳的

―例如:if let Some(x) = a_value

函数参数、let语句、for循环只接受无可辩驳的模式

if let和l while let接受可辨驳和无可辩驳的模式

fn main() {
    let a:Option<i32> = Some(5);

    let Some(x) = a;
}

let是无可辩驳的模式

Some是可辩驳的模式

fn main() {
    let a:Option<i32> = Some(5);

    if let Some(x) = a {
        
    }
}

我们改成if let的模式就可以通过编译了

if let的是可失败的

3、模式语法

匹配字面值

模式可直接匹配字面值

fn main() {
    let x = 1;

    match x {
        1 => println!("1"),
        2 => println!("2"),
        3 => println!("3"),
        _ => println!("anything"),
    }
}

匹配命名变量

命名的变量是可匹配任何值的无可辩驳模式

fn main() {
    let x = Some(5);
    let y = 10;



    match x {
        Some(5) => println!("5"),
        Some(y) => println!("y:{}",y),
        _ => println!("{:?}",x),
    }

    println!("{:?},{:?}",x,y);
}

多重模式

在 match表达式中,使用│语法(就是或的意思),可以匹配多种模式

fn main() {
    let x = 1;

    match x {
        1|2 => println!("one or two"),
        3 => println!("three"),
        _ => println!("{:?}",x),
    }
}

使用..=来匹配某个范围的值

fn main() {
    let x = 5;

    match x {
       1..=5 => println!("one througth five"),
       _ => println!("something else"),
    }

    let x = 'c';
    match x {
        'a'..='j' => println!("early ASCII Letter"),
        'k'..='z' => println!("late ASCII Letter"),
        _ => println!("somthing else")
    }

}

解构以分解值

可以使用模式来解构struct、enum、tuple,从而引用这些类型值的不同部分

struct Point {
    x:i32,
    y:i32
}

fn main() {
    let p = Point {x:0,y:7};

    // let Point {x:a,y:b} = p;

    // assert_eq!(0,a);
    // assert_eq!(7,b);

    // let Point {x,y} = p;

    // assert_eq!(0,a);
    // assert_eq!(7,b);

    match p {
        Point{x,y:0} => println!("On the x axis at {}",x),
        Point{x:0,y} => println!("On the y axis at {}",y),
        Point{x,y} => println!("On neither axis ({},{})",x,y),
    }


}

解构enum

enum Message {
    Quit,
    Move{x:i32,y:i32},
    Write(String),
    ChangeColor(i32,i32,i32),
}

fn main() {
    let msg = Message::ChangeColor(0, 160, 255);

    match msg {
        Message::Quit => {
            println!("The Quit variant has no data to destucture.");
        },
        Message::Move{x,y} => {
            println!("x:{},y:{}",x,y);
        },
        Message::Write(text) => println!("Text message:{}",text),
        Message::ChangeColor(r,g,b) => {
            println!("r:{},g:{},b:{}",r,g,b);
        },
    }

}

解构嵌套的struct和 enum

 

enum Color {
    Rgb(i32,i32,i32),
    Hsv(i32,i32,i32),
}
enum Message {
    Quit,
    Move{x:i32,y:i32},
    Write(String),
    ChangeColor(Color),
}

fn main() {
    let msg = Message::ChangeColor(Color::Hsv(0, 160, 255));

    match msg {
        Message::ChangeColor(Color::Rgb(r,g,b)) => {
            println!("r:{},g:{},b:{}",r,g,b);
        },
        Message::ChangeColor(Color::Hsv(r,g,b)) => {
            println!("r:{},g:{},b:{}",r,g,b);
        },
        _=>()
    }

}

解构struct和 tuple

struct Point {
    x:i32,
    y:i32,
}

fn main() {
    let ((feet,inches),Point{x,y}) = ((3,10),Point{x:3,y:-10});

}

在模式中忽略值

有几种方式可以模式中忽略整个值或部分值:

_

_配合其它模式

使用以_开头的名称

..(忽略值的剩余部分)

使用_来忽略整个值

fn foo(_:i32,y:i32) {
    println!("This y value is :{}",y);
}

fn main() {
    foo(3, 4);

}

使用嵌套的_来忽略值的一部分

fn main() {
    let mut setting_value = Some(5);
    let mut new_setting_value = Some(5);

    match (setting_value,new_setting_value) {
        (Some(_),Some(_)) => {
            println!("can't overwrite an existing customized value");
        }
        _=>{
            setting_value = new_setting_value;
        }
    }

    println!("setting is {:?}",setting_value);

    let numbers = (2,3,4,5,6);

    match numbers {
        (first,_,thrid,_,fifth) => {
            println!("Some numbers:{},{},{}",first,thrid,fifth);
        }
    }

}

通过使用_开头命名来忽略未使用的变量

fn main() {
    // let _x = 5;
    // let y = 10;

    let s = Some(String::from("Hello!"));

    if let Some(_) = s {
        println!("found a string");
    }

    println!("{:?}",s);

}

使用..来忽略值的剩余部分

 

struct Point {
    x:i32,
    y:i32,
    z:i32
}

fn main() {
   let origin = Point{x:0,y:0,z:0};

   match origin {
       Point{x,..}=>println!("x is {}",x),
   }

   let numbers = (2,4,6,8,10);
   match numbers {
       (first,..,last) => {
        println!("Some numbers:{},{}",first,last);
       }
   }

//    match numbers {
//         (..,second,..) => {
//         println!("Some numbers:{}",second);
//         }
//     }

}

使用match守卫来提供额外的条件

match守卫就是match arm模式后额外的if条件,想要匹配该条件也必须满足

match守卫适用于比单独的模式更复杂的场景

// fn main() {
//     let num = Some(4);

//     match num {
//         Some(x) if x < 5 => println!("less than five:{}",x),
//         Some(x)=>println!("{}",x),
//         None=>(),
//     }
// }

// fn main() {
//     let x = Some(5);

//     let y = 10;

//     match x {
//         Some(50) => println!("Got 50"),
//         Some(n) if n ==y =>println!("Matched,n={:?}",n),
//         _=>println!("Default case,x={:?}",x),  
//     }

//     println!("at the end:x={:?},y={:?}",x,y);
// }

fn main() {
    let x = 4;
    let y = false;

    match x {
       4 | 5 | 6 if y => println!("yes"),
       _=>println!("no")
    }
}

@绑定

@符号让我们可以创建一个变量,该变量可以在测试某个值是否与模式匹配的同时保存该值

enum Message {
    Hello{id:i32},
}

fn main() {
   let msg = Message::Hello { id: 5 };

   match msg {
       Message::Hello { 
            id:id_variable @ 3..=7,
        } => {
            println!("Found an id in range:{}",id_variable)
        }

        Message::Hello { id:10..=12} => {
            println!("Found an id another range")
        }
        Message::Hello { id} => {
            println!("Found some other id:{}",id)
        }
   }
}


 

 

你好:我的2025

上一篇:Rust的面向对象

下一篇:Rust的Unsafe Rust