rust(十八)-模式匹配

143 阅读5分钟

模式

  • 模式是RUST中的一种特殊语法,用于匹配复杂和简单类型的结构
  • 将模式与匹配表达式和其他构造结合使用,可以更好地控制程序的控制流
  • 模式同以下元素(的一些组合)组成:
    • 字面值
    • 解构的数组、enum、struct 和 tuple
    • 变量
    • 通配符
    • 占位符
  • 想要使用模式,需要将其与某个值进行比较

能用到模式的地方

  • match的Arm
    match VALUE {
          PATTERN => EXPRESSION,
          PATTERN => EXPRESSION,
          PATTERN => EXPRESSION,
      }
    
  • match表达式的要求:
    • 详尽(包含所有的可能性)
  • 一个特殊的模式:_(下划线):
    • 它会匹配任何东西
    • 不会绑定到变量
    • 能常用于match的最后一个arm;或用于忽略某些值

条件 if let表达式

  • if let表态式主要是作为一种简短的方式来等价的代替只有一个匹配项的match
  • if 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!("Using your favorite color, {}, as the background", color);
    } else if is_tuesday {
        println!("Tuesday is green day!");
    } else if let Ok(age) = age {
        if age > 30 {
            println!("Using purple as the background color");
        } else {
            println!("Using orange as the background color");
        }
    } else {
        println!("Using blue as the background color");
    }
}

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 (x, y, z) = (1, 2, 3);
}

函数参数

  • 函数参数也可以是模式
fn print_coordinates(&(x, y): &(i32, i32)) {
    println!("Current location: ({}, {})", x, y);
}

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

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

  • 模式的两种形式
    • 模式有两种形式: 可辩驳的,无可辩驳的
    • 能匹配任何可能传递的值的模式:无可辩驳的
    • 对某些可能的值,无法进行匹配的模式:可辩驳的
      • 例如: if let some(x) = a_value
    • 函数参数、let语句、for循环只接受无可辩驳的模式

模式语法

  • 匹配字面值
fn main() {
    let x = 1;

    match x {
        1 => println!("one"),
        2 => println!("two"),
        3 => println!("three"),
        _ => println!("anything"),
    }
}
  • 匹配命名变量
    • 命名的变量是可匹配任何值的无可辩驳模式
    fn main() {
      let x = Some(5);
      let y = 10;
    
      match x {
          Some(50) => println!("Got 50"),
          Some(y) => println!("Matched, y = {:?}", y),
          _ => println!("Default case, x = {:?}", x),
      }
    
      println!("at the end: x = {:?}, y = {:?}", x, y);
    }
    
  • 多重模式
    • 在match表达试中,使用|语法(就是或的意思),可以匹配多种模式
    fn main() {
     let x = 1;
    
     match x {
         1 | 2 => println!("one or two"),
         3 => println!("three"),
         _ => println!("anything"),
     }
    }
    
  • 使用 ..=来匹配某个范围的值
fn main() {
   let x = 'c';

   match x {
       'a'..='j' => println!("early ASCII letter"),
       'k'..='z' => println!("late ASCII letter"),
       _ => println!("something 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);
      }
     struct Point {
      x: i32,
      y: i32,
     }
    
     fn main() {
      let p = Point { x: 0, y: 7 };
    
      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 destructure.")
              }
              Message::Move { x, y } => {
                  println!(
                      "Move in the x direction {} and in the y direction {}",
                      x, y
                  );
              }
              Message::Write(text) => println!("Text message: {}", text),
              Message::ChangeColor(r, g, b) => println!(
                  "Change the color to red {}, green {}, and blue {}",
                  r, g, b
              ),
          }
      }
      
    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!(
                  "Change the color to red {}, green {}, and blue {}",
                  r, g, b
              ),
              Message::ChangeColor(Color::Hsv(h, s, v)) => println!(
                  "Change the color to hue {}, saturation {}, and value {}",
                  h, s, v
              ),
              _ => (),
          }
      }
    
    
    • 解构struct和tuple
    fn foo(_: i32, y: i32) {
      println!("This code only uses the y parameter: {}", y);
      }
    
      fn main() {
          foo(3, 4);
      }
    
    
  • 在模式中忽略值
    • 有几种方式可以模式中忽略整个值或部分值:
    • _
     fn foo(_: i32, y: i32) {
         println!("This code only uses the y parameter: {}", y);
     }
    
     fn main() {
         foo(3, 4);
     }
    
    • _配合其它模式
     fn main() {
     let mut setting_value = Some(5);
     let new_setting_value = Some(10);
    
     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);
    }
    
    • 使用以_开头的名称
    fn main() {
     let s = Some(String::from("Hello!"));
    
     if let Some(_) = s {
         println!("found a string");
     }
    
     println!("{:?}", s);
    }
    
    
    • .. (忽略值的剩余部分)
    fn main() {
     struct Point {
         x: i32,
         y: i32,
         z: i32,
     }
    
     let origin = Point { x: 0, y: 0, z: 0 };
    
     match origin {
         Point { x, .. } => println!("x is {}", x),
     }
    }
    
    
  • 使用match守卫来提供额外的条件
    • match守卫主是match arm模式后额外的if条件,想要匹配条件也必须满足
    • match守卫适用于比单独的模式更复杂的场景
    fn main() {
      let num = Some(4);
    
      match num {
          Some(x) if x % 2 == 0 => println!("The number {} is even", x),
          Some(x) => println!("The number {} is odd", x),
          None => (),
      }
    }
    
    

@ 绑定

  • @符号让我们可以创建一个变量,该变量可以在测试某个值是否与模式匹配的同时保存该值
fn main() {
      enum Message {
          Hello { id: i32 },
      }

      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 in another range")
          }
          Message::Hello { id } => println!("Found some other id: {}", id),
      }
  }