返回介绍

3.3 匹配

发布于 2024-10-13 11:25:28 字数 4399 浏览 0 评论 0 收藏 0

类似 switch ,将值与多个模式比较,依匹配结果执行分支代码。模式可以是变量、字面量、通配符,或其他内容。

match VALUE {
  PATTERN => EXPRESSION,
  ...
}

限制:

  • 模式必须覆盖(cover)所有值。
  • 分支代码是表达式,其结果作为返回值。
  • 分支代码块(block)以逗号结束。
  • _ 实现默认(default)分支。

重复模式会输出警告信息 unreachable pattern,不会出错。默认分支必须放在最后,否则也会导致 unreachable pattern。

fn main() {
  let x = 3;

  match x {
    1   => println!("1"),
    2   => println!("2"),
    3 | 4 => println!("3 | 4"),  // or
    _   => {},         // 放在最后!
  }
}
let x = 1;

match x {
  1 ..= 5 => println!("1 ... 5"),   // range
  _     => println!("..."),
}

可用于赋值。

let x = 5;

let number = match x {
  1 => "one",
  2 => "two",
  3 => "three",
  4 => "four",
  5 => "five",
  _ => "something else",
};

模式

相比其他语言的 switch 语句,match 和 pattern 结合,可优雅完成解构操作。

考虑到 value 可能是个表达式,所以分支定义一个接收值的局部变量很有必要。

fn main() {
  let x = 1;
  let c = ||{ 'c' };           // 匿名函数。

  match c() {
    x => println!("{}, {:p}", x, &x),  // let x = c()
  }                    // 匹配所有值。

  println!("{}, {:p}", x, &x)      // 地址不同!
}

// c, 0x7fff50a16e7c
// 1, 0x7fff50a16e78

解构复合类型。

枚举成员可附加额外数据,诸如单值、元组或结构。

enum X {        
  A(i32, String),   
  B{x: i32, y: i32},
}

fn main() {
  let x = X::B{ x: 11, y: 22 };

  match x {
    X::A(a, b) => println!("{} {}", a, b),
    X::B{x, y} => println!("{} {}", x, y),   // 或 X::B{x:a, y:b} => a, b
  }
}
fn main() {
  let d = (1, 2, 3, 4);
  match d {
    (x, .., y) => println!("{}..{}", x, y),   // 解构元组局部元素。
    // (x, ..) => println!("{}", x),
    // (.., y) => println!("{}", y),
  }
}

// 1..4
struct Point {
  x: i32,
  y: i32,
}

let origin = Point { x: 1, y: 2 };

match origin {
  Point{x, y} => println!("{},{}", x, y),  // 或 Point{x:a, y:b} => a, b
}                      // 部分忽略:Point{x, ..} =>
                       // 匹配类型:Point{..} =>
                       // 单个忽略:_

匹配类型要写成 T{..} ,光有类型名会被当作局部变量。

增加匹配条件,诸如部分值、范围、选择条件等。

fn main() {
  let d = [1, 2, 3, 4, 5, 6]; 

  match d {
    [0, 1, 2, ..] => println!("a"),
    [.., 6, 7]  => println!("b"),
    [1, .., 6]  => println!("c"),
    _       => println!("n"),
  }
}

// c
fn main() {
  struct Foo {
    x: (u32, u32),
    y: u32,
  }

  let foo = Foo { x: (1, 2), y: 3 };

  match foo {
    Foo{ x: (1, b), y } => println!("{}, {} ", b, y),  // 含部分值的深层解构。
    Foo{ y: 2, x: i }   => println!("{}", i.0),
    Foo{ y, .. }    => println!("{}", y),
  }
}

// 2, 3
fn main() {
  let x = 4;

  match x {
    n @ 1 ..= 5 => println!("a: {}", n),
    n       => println!("b: {}", n),  // 其他(可用 _ 忽略)
  }
}

// a: 4
fn main() {
  let x = 5;

  match x {
    1 ..= 10 if x % 2 == 0 => println!("a"),
    n if n > 10      => println!("b"),
    _            => println!("c"),
  }
}

// c

获取引用与匹配引用的区别。

fn main() {
  let v = 100;
  match v {
    ref r => println!("{}", *r),  // r: &i32  获取引用!
  }                 // 代替所有权转移或复制。
                    // 可变引用: ref mut r
  let r = &v;
  match r {
    &v => println!("{}", v),   // v: i32  匹配引用,取值!
  }                // 要求 value/r 必须是引用。
}

简单匹配

如果只关心单个模式,可用 if-letwhile-let 代替,更简洁。

if let PATTERN = EXPRESSION {
  /* body */
} else {
  /*else */
}
match EXPRESSION {
  PATTERN => { /* body */ },
  _     => { /* else */ },  // () if there is no else
}

相比直接用 if ,多了模式解构操作。

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

fn main() {
  let p = Point {x: 1, y: 2};

  match p {
    Point{x, y: 2} => println!("{}", x),
    _ => {},
  }

  if let Point{x: n, y: 2} = p {  // 判断类型和 y 值,解构。
    println!("{}", n);
  }
}
fn main() {
  let mut x = vec![1, 2, 3];

  while let Some(n) = x.pop() {
    println!("{:?}", n);
  }
}

注意解构临时变量作用域。

fn main() {
  let p = Point {x: 1, y: 2};

  if let Point{x: n, y: 100} = p {
    println!("T: {}", n);
  } else {
    println!("F: {}", n);
              ^ cannot find value `n` in this scope
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文