💻博主现有专栏:
C51单片机(STC89C516),c语言,c++,离散数学,算法设计与分析,数据结构,Python,Java基础,MySQL,linux,基于HTML5的网页设计及应用,Rust(官方文档重点总结),jQuery,前端vue.js,Javaweb开发,Python机器学习等
🥏主页链接:
目录
🎯match分支
一个模式常用的位置是
match
表达式的分支。在形式上match
表达式由match
关键字、用于匹配的值和一个或多个分支构成,这些分支包含一个模式和在值匹配分支的模式时运行的表达式:match VALUE { PATTERN => EXPRESSION, PATTERN => EXPRESSION, PATTERN => EXPRESSION, }
match x { None => None, Some(i) => Some(i + 1), }
这个
match
表达式中的模式为每个箭头左边的None
和Some(i)
。
match
表达式必须是 穷尽(exhaustive)的,意为match
表达式所有可能的值都必须被考虑到。一个确保覆盖每个可能值的方法是在最后一个分支使用捕获所有的模式:比如,一个匹配任何值的名称永远也不会失败,因此可以覆盖所有匹配剩下的情况。
🎯if let 条件表达式
以前讨论过了
if let
表达式,以及它是如何主要用于编写等同于只关心一个情况的match
语句简写的。if let
可以对应一个可选的带有代码的else
在if let
中的模式不匹配时运行。这相比
match
表达式一次只能将一个值与模式比较提供了更多灵活性。并且 Rust 并不要求一系列if let
、else if
、else 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, {color}, as the background"); } 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"); } }
如果用户指定了中意的颜色,将使用其作为背景颜色。如果没有指定中意的颜色且今天是星期二,背景颜色将是绿色。如果用户指定了他们的年龄字符串并能够成功将其解析为数字的话,我们将根据这个数字使用紫色或者橙色。最后,如果没有一个条件符合,背景颜色将是蓝色。
这个条件结构允许我们支持复杂的需求。使用这里硬编码的值,例子会打印出
Using purple as the background color
。注意
if let
也可以像match
分支那样引入覆盖变量:if let Ok(age) = age
引入了一个新的覆盖变量age
,它包含Ok
成员中的值。这意味着if age > 30
条件需要位于这个代码块内部;不能将两个条件组合为if let Ok(age) = age && age > 30
,因为我们希望与 30 进行比较的被覆盖的age
直到大括号开始的新作用域才是有效的。
if let
表达式的缺点在于其穷尽性没有为编译器所检查,而match
表达式则检查了。如果去掉最后的else
块而遗漏处理一些情况,编译器也不会警告这类可能的逻辑错误。
🎯while let条件循环
它使用 vector 作为栈并以先进后出的方式打印出 vector 中的值:
let mut stack = Vec::new(); stack.push(1); stack.push(2); stack.push(3); while let Some(top) = stack.pop() { println!("{}", top); }
这个例子会打印出 3、2 接着是 1。
pop
方法取出 vector 的最后一个元素并返回Some(value)
。如果 vector 是空的,它返回None
。while
循环只要pop
返回Some
就会一直运行其块中的代码。一旦其返回None
,while
循环停止。我们可以使用while let
来弹出栈中的每一个元素。
🎯for循环
在
for
循环中,模式是for
关键字直接跟随的值,正如for x in y
中的x
。let v = vec!['a', 'b', 'c']; for (index, value) in v.iter().enumerate() { println!("{} is at index {}", value, index); }
会打印:
$ cargo run Compiling patterns v0.1.0 (file:///projects/patterns) Finished dev [unoptimized + debuginfo] target(s) in 0.52s Running `target/debug/patterns` a is at index 0 b is at index 1 c is at index 2
🎯let语句
在本章之前,我们只明确的讨论过通过
match
和if let
使用模式,不过事实上也在别的地方使用过模式,包括let
语句。例如,考虑一下这个直白的let
变量赋值:let x = 5;
不过你可能没有发觉,每一次像这样使用
let
语句就是在使用模式!let
语句更为正式的样子如下:let PATTERN = EXPRESSION;
像
let x = 5;
这样的语句中变量名位于PATTERN
位置,变量名不过是形式特别朴素的模式。我们将表达式与模式比较,并为任何找到的名称赋值。所以例如let x = 5;
的情况,x
是一个代表 “将匹配到的值绑定到变量 x” 的模式。同时因为名称x
是整个模式,这个模式实际上等于 “将任何值绑定到变量x
,不管值是什么”。为了更清楚的理解
let
的模式匹配方面的内容,考虑示例 18-4 中使用let
和模式解构一个元组:let (x, y, z) = (1, 2, 3);
这里将一个元组与模式匹配。Rust 会比较值
(1, 2, 3)
与模式(x, y, z)
并发现此值匹配这个模式。在这个例子中,将会把1
绑定到x
,2
绑定到y
并将3
绑定到z
。你可以将这个元组模式看作是将三个独立的变量模式结合在一起。如果模式中元素的数量不匹配元组中元素的数量,则整个类型不匹配,并会得到一个编译时错误。
let (x, y) = (1, 2, 3);
尝试编译这段代码会给出如下类型错误:
$ cargo run Compiling patterns v0.1.0 (file:///projects/patterns) error[E0308]: mismatched types --> src/main.rs:2:9 | 2 | let (x, y) = (1, 2, 3); | ^^^^^^ --------- this expression has type `({integer}, {integer}, {integer})` | | | expected a tuple with 3 elements, found one with 2 elements | = note: expected tuple `({integer}, {integer}, {integer})` found tuple `(_, _)` For more information about this error, try `rustc --explain E0308`. error: could not compile `patterns` due to previous error
为了修复这个错误,可以使用
_
或..
来忽略元组中一个或多个值
🎯函数参数
它获取一个
i32
类型的参数x
,现在这看起来应该很熟悉:fn foo(x: i32) { // code goes here }
x
部分就是一个模式!类似于之前对let
所做的,可以在函数参数中匹配元组。fn print_coordinates(&(x, y): &(i32, i32)) { println!("Current location: ({}, {})", x, y); } fn main() { let point = (3, 5); print_coordinates(&point); }
这会打印出
Current location: (3, 5)
。值&(3, 5)
会匹配模式&(x, y)
,如此x
得到了值3
,而y
得到了值5
。