5分钟速读之Rust权威指南(十)

273 阅读3分钟

控制流match 和 if let

rust中有一个强大的控制流运算符:match,它允许将一个值与一系列的模式相比较,并根据匹配的模式执行相应代码,模式可由字面量、变量名、通配符和许多其他东西组成(后面章节会详细介绍)。

match的简单使用

我们将创建一个包含3中web框架的枚举,根据枚举变体类型获取框架最新版本号:

// 定义一个框架枚举,包含3种框架的变体
enum Framework {
	Vue,
	Angular,
	React
}

fn framework_version(framework: Framework) -> u32 {
  // 使用match关键字对framework进行匹配
	match framework {
    // 模式 => 处理逻辑
		Framework::Vue => 3,
		Framework::Angular => 12,
		Framework::React => { // 多行代码可以添加花括号
			return 17
		},
	}
}

println!("Vue: {}", framework_version(Framework::Vue)); // 3
println!("Angular: {}", framework_version(Framework::Angular)); // 12
println!("React: {}", framework_version(Framework::React)); // 17

绑定值的模式

match还可以绑定被匹配对象的部分值,而这也正是我们用于从枚举变体中提取值的方法:

#[derive(Debug)]
enum VueState { // Vue框架的状态
  Stable,
  Next,
}

enum Framework {
  Vue(VueState), // Vue框架变体关联一个状态类型
  Angular,
  React
}

fn framework_version(framework: Framework) -> u32 {
  match framework {
    Framework::Angular => 12,
    Framework::React => 17,
    Framework::Vue(state) => { // 首先匹配到Vue分支,然后将Next绑定到state上
      match state { // 继续匹配state
        VueState::Stable => 2,
        VueState::Next => 3,
      }
    }
  }
}

// 创建不同状态的Vue枚举
let vue2 = Framework::Vue(VueState::Stable);
let vue3 = Framework::Vue(VueState::Next);

println!("{}", framework_version(vue2)); // 2
println!("{}", framework_version(vue2)); // 3

匹配Option

上一章节中介绍过的Option,match也可以将Option::Some(T)中的T值取出:

fn unwrap(x: Option<i32>) -> i32 {
	match x {
		Option::None => 0, // 当是变体None时,返回0
		Option::Some(num) => { // five匹配到Some分支,然后将5匹配到num上
			num
		},
	}
}

let option_five = Option::Some(5);
let five = unwrap(option_five);
let zero = unwrap(None);

println!("{:?}", option_five); // Some(5)
println!("{}", five); // 5
println!("{}", zero); // 0

匹配必须穷举的所有可能

如果没有穷举(exhaustive)所有值,将会编译失败:

match framework {
	Framework::Vue => 3,
	Framework::Angular => 12,
  // 报错,Framework::React 情况未覆盖
}

_通配符

有的时候,我们可能并不想要处理所有可能的值,rust同样也提供了一种模式用于处理这种需求:

let some_u8_value = 10u8;
match some_u8_value {
	1 => println!("one"),
	2 => println!("two"),
	3 => println!("three"),
	// 因为u8有255中可能,我们肯定不会穷举所有,只列出关心的即可,其他的用_代替
	_ => println!("other")
}
// "other"

if let 语法糖

由于match的穷举性要求,当我们只关心某一种情况时,代码写起来还是比较繁琐,这时我们可以使用if let语法糖来解决:

let some_u8_value = Option::Some(3u8);

// match方式
match some_u8_value {
	Option::Some(3u8) => println!("three"),
	_ => println!("other")
}
// "three"

// if let方式
if let Option::Some(3) = some_u8_value {
	println!("three")
} else {
  // else是可选的,相当于match分支中的 _ => println!("other")
	println!("other")
}
// "three"

我们再看一下最上边web框架的例子,使用if let代替match:

let vue2 = Framework::Vue(VueState::Stable);
let vue3 = Framework::Vue(VueState::Next);

// match方式
match vue2 {
  Framework::Vue(state) => {
    println!("{:?}", state)
  }
  _ => println!("other")
}
// Stable

// if let方式
if let Framework::Vue(state) = vue3 {
  println!("{:?}", state)
} else {
  println!("other")
}
// Next