网站开发技术负责那些,徐州网站开发信息,在线学习网站开发,长沙网站推广文章目录 4 流程控制4.1 if else表达式4.2 循环控制4.2.1 for循环4.2.2 while循环4.2.3 loop循环 5 模式匹配5.1 match和if let5.1.1 match匹配使用match表达式赋值模式绑定_通配符 5.1.2 if let 匹配5.1.3 matches! 宏 5.2 解构Option5.3 认识模式match 分支if let 分支while … 文章目录 4 流程控制4.1 if else表达式4.2 循环控制4.2.1 for循环4.2.2 while循环4.2.3 loop循环 5 模式匹配5.1 match和if let5.1.1 match匹配使用match表达式赋值模式绑定_通配符 5.1.2 if let 匹配5.1.3 matches! 宏 5.2 解构Option5.3 认识模式match 分支if let 分支while let 条件循环for 循环let 语句函数参数let 和 if let 5.3 [全模式列表](https://course.rs/basic/match-pattern/all-patterns.html) 4 流程控制
4.1 if else表达式
if condition true {// A...
} else {// B...
}该代码读作若 condition 的值为 true则执行 A 代码否则执行 B 代码。例如
fn main() {let condition true;let number if condition {5} else {6};println!(The value of number is: {}, number);
}if 语句块是表达式这里我们使用 if 表达式的返回值来给 number 进行赋值number 的值是 5用 if 来赋值时要保证每个分支返回的类型一样(事实上这种说法不完全准确见这里)此处返回的 5 和 6 就是同一个类型如果返回类型不一致就会报错
可以将 else if 与 if、else 组合在一起实现更复杂的条件分支判断
4.2 循环控制
4.2.1 for循环
核心就在于 for 和 in 的联动语义表达如下
for 元素 in 集合 {// 使用元素干一些你懂我不懂的事情
}例如
fn main() {for i in 1..5 {println!({}, i);}
}以上代码循环输出一个从 1 到 5 的序列。
注意使用 for 时我们往往使用集合的引用形式除非你不想在后面的代码中继续使用该集合比如我们这里使用了 container 的引用。如果不使用引用的话所有权会被转移move到 for 语句块中后面就无法再使用这个集合了)
如果想在循环中修改该元素可以使用 mut 关键字
for item in mut collection {// ...
}总结如下
使用方法等价使用方式所有权for item in collectionfor item in IntoIterator::into_iter(collection)转移所有权for item in collectionfor item in collection.iter()不可变借用for item in mut collectionfor item in collection.iter_mut()可变借用
如果想在循环中获取元素的索引
fn main() {let a [4, 3, 2, 1];// .iter() 方法把 a 数组变成一个迭代器for (i, v) in a.iter().enumerate() {println!(第{}个元素是{}, i 1, v);}
}两种循环方式
// 第一种
let collection [1, 2, 3, 4, 5];
for i in 0..collection.len() {let item collection[i];// ...
}// 第二种
for item in collection {}第一种方式是循环索引然后通过索引下标去访问集合第二种方式是直接循环集合中的元素优劣如下
性能第一种使用方式中 collection[index] 的索引访问会因为边界检查(Bounds Checking)导致运行时的性能损耗 —— Rust 会检查并确认 index 是否落在集合内但是第二种直接迭代的方式就不会触发这种检查因为编译器会在编译时就完成分析并证明这种访问是合法的安全第一种方式里对 collection 的索引访问是非连续的存在一定可能性在两次访问之间collection 发生了变化导致脏数据产生。而第二种直接迭代的方式是连续访问因此不存在这种风险
使用 continue 可以跳过当前当次的循环开始下次的循环使用 break 可以直接跳出当前整个循环
4.2.2 while循环
如果你需要一个条件来循环当该条件为 true 时继续循环条件为 false跳出循环那么 while 就非常适用
fn main() {let mut n 0;while n 5 {println!({}!, n);n n 1;}println!(我出来了);
}4.2.3 loop循环
loop 就是一个简单的无限循环你可以在内部实现逻辑通过 break 关键字来控制循环何时结束。当使用 loop 时必不可少的伙伴是 break 关键字它能让循环在满足某个条件时跳出
fn main() {let mut counter 0;let result loop {counter 1;if counter 10 {break counter * 2;}};println!(The result is {}, result);
}以上代码当 counter 递增到 10 时就会通过 break 返回一个 counter * 2 的值最后赋给 result 并打印出来。
这里有几点值得注意
break 可以单独使用也可以带一个返回值有些类似 returnloop 是一个表达式因此可以返回一个值
5 模式匹配
5.1 match和if let
5.1.1 match匹配
match 的通用形式
match target {模式1 表达式1,模式2 {语句1;语句2;表达式2},_ 表达式3
}该形式清晰的说明了何为模式何为模式匹配将模式与 target 进行匹配即为模式匹配
match 的匹配必须要穷举出所有可能因此这里用 _ 来代表未列出的所有可能性match 的每一个分支都必须是一个表达式且所有分支的表达式最终返回值的类型必须相同
使用match表达式赋值
match 本身也是一个表达式因此可以用它来赋值
enum IpAddr {Ipv4,Ipv6
}fn main() {let ip1 IpAddr::Ipv6;let ip_str match ip1 {IpAddr::Ipv4 127.0.0.1,_ ::1,};println!({}, ip_str);
}因为这里匹配到 _ 分支所以将 ::1 赋值给了 ip_str。
模式绑定
模式匹配的一个重要功能是从模式中取出绑定的值。
模式绑定的例子
enum Action {Say(String),MoveTo(i32, i32),ChangeColorRGB(u16, u16, u16),
}fn main() {let actions [Action::Say(Hello Rust.to_string()),Action::MoveTo(1,2),Action::ChangeColorRGB(255,255,0),];for action in actions {match action {Action::Say(s) {println!({}, s);},Action::MoveTo(x, y) {println!(point from (0, 0) move to ({}, {}), x, y);},Action::ChangeColorRGB(r, g, _) {println!(change color into (r:{}, g:{}, b:0), b has been ignored,r, g,);}}}
}运行后输出
$ cargo runCompiling world_hello v0.1.0 (/Users/sunfei/development/rust/world_hello)Finished dev [unoptimized debuginfo] target(s) in 0.16sRunning target/debug/world_hello
Hello Rust
point from (0, 0) move to (1, 2)
change color into (r:255, g:255, b:0), b has been ignored
_通配符
match 的匹配必须穷尽所有情况即穷尽匹配Rust 编译器清晰地知道 match 中有哪些分支没有被覆盖, 这种行为能强制我们处理所有的可能性。
通过将 _ 其放置于其他分支后_ 将会匹配所有遗漏的值。() 表示返回单元类型与所有分支返回值的类型相同所以当匹配到 _ 后什么也不会发生。
5.1.2 if let 匹配
有时会遇到只有一个模式的值需要被处理其它值直接忽略的场景如果用 match 来处理就要写成下面这样 let v Some(3u8);match v {Some(3) println!(three),_ (),}我们只想要对 Some(3) 模式进行匹配, 不想处理任何其他 Someu8 值或 None 值。但是为了满足 match 表达式穷尽性的要求写代码时必须在处理完这唯一的成员后加上 _ ()这样会增加不少无用的代码。
俗话说“杀鸡焉用牛刀”我们完全可以用 if let 的方式来实现
if let Some(3) v {println!(three);
}这两种匹配对于新手来说可能有些难以抉择但是只要记住一点就好当你只要匹配一个条件且忽略其他条件时就用 if let 否则都用 match。
无论是 match 还是 if let他们都可以在模式匹配时覆盖掉老的值绑定新的值:
fn main() {let ageSome(30);let b3;println!(匹配前b{:?},b); //3if let bage{println!(b:{:?},b); //Some(30)}println!(匹配后b{:?},b); //3
}5.1.3 matches! 宏
matches!宏可以将一个表达式跟模式进行匹配然后返回匹配的结果 true or false。
例如
let foo f;
assert!(matches!(foo, A..Z | a..z));let bar Some(4);
assert!(matches!(bar, Some(x) if x 2));5.2 解构Option
Opention枚举用来解决Rust中变量是否有值的问题定义如下
enum OptionT {Some(T),None,
}简单解释就是一个变量要么有值Some(T), 要么为空None。
使用 OptionT是为了从 Some 中取出其内部的 T 值以及处理没有值的情况为了演示这一点下面一起来编写一个函数它获取一个 Optioni32如果其中含有一个值将其加一如果其中没有值则函数返回 None 值
fn plus_one(x: Optioni32) - Optioni32 {match x {None None,Some(i) Some(i 1),}
}let five Some(5);
let six plus_one(five);
let none plus_one(None);plus_one 接受一个 Optioni32 类型的参数同时返回一个 Optioni32 类型的值(这种形式的函数在标准库内随处所见)在该函数的内部处理中如果传入的是一个 None 则返回一个 None 且不做任何处理如果传入的是一个 Some(i32)则通过模式绑定把其中的值绑定到变量 i 上然后返回 i1 的值同时用 Some 进行包裹。
5.3 认识模式
模式是 Rust 中的特殊语法它用来匹配类型中的结构和数据模式一般由以下内容组合而成
字面值解构的数组、枚举、结构体或者元组变量通配符占位符
所有可能认识到模式的地方
match 分支
match VALUE {PATTERN EXPRESSION,PATTERN EXPRESSION,PATTERN EXPRESSION,
}如上所示match 的每个分支就是一个模式因为 match 匹配是穷尽式的因此我们往往需要一个特殊的模式 _来匹配剩余的所有情况
match VALUE {PATTERN EXPRESSION,PATTERN EXPRESSION,_ EXPRESSION,
}if let 分支
if let 往往用于匹配一个模式而忽略剩下的所有模式的场景
if let PATTERN SOME_VALUE {}while let 条件循环
一个与 if let 类似的结构是 while let 条件循环它允许只要模式匹配就一直进行 while 循环。下面展示了一个使用 while let 的例子
// Vec是动态数组
let mut stack Vec::new();// 向数组尾部插入元素
stack.push(1);
stack.push(2);
stack.push(3);// stack.pop从数组尾部弹出元素
while let Some(top) stack.pop() {println!({}, top);
}这个例子会打印出 3、2 接着是 1。pop 方法取出动态数组的最后一个元素并返回 Some(value)如果动态数组是空的将返回 None对于 while 来说只要 pop 返回 Some 就会一直不停的循环。一旦其返回 Nonewhile 循环停止。可以使用 while let 来弹出栈中的每一个元素。
for 循环
let v vec![a, b, c];for (index, value) in v.iter().enumerate() {println!({} is at index {}, value, index);
}这里使用 enumerate 方法产生一个迭代器该迭代器每次迭代会返回一个 (索引值) 形式的元组然后用 (index,value) 来匹配。
let 语句
let PATTERN EXPRESSION;是的 该语句我们已经用了无数次了它也是一种模式匹配
let x 5;这其中x 也是一种模式绑定代表将匹配的值绑定到变量 x 上。因此在 Rust 中,变量名也是一种模式只不过它比较朴素很不起眼罢了。
let (x, y, z) (1, 2, 3);上面将一个元组与模式进行匹配(模式和值的类型必需相同)然后把 1, 2, 3 分别绑定到 x, y, z 上。
模式匹配要求两边的类型必须相同否则就会导致下面的报错
let (x, y) (1, 2, 3);
error[E0308]: mismatched types-- src/main.rs:4:5|
4 | 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 playground due to previous error对于元组来说元素个数也是类型的一部分
函数参数
函数参数也是模式
fn foo(x: i32) {// 代码
}其中 x 就是一个模式你还可以在参数中匹配元组
fn print_coordinates((x, y): (i32, i32)) {println!(Current location: ({}, {}), x, y);
}fn main() {let point (3, 5);print_coordinates(point);
}(3, 5) 会匹配模式 (x, y)因此 x 得到了 3y 得到了 5。
let 和 if let
对于以下代码编译器会报错
let Some(x) some_option_value;因为右边的值可能不为 Some而是 None这种时候就不能进行匹配也就是上面的代码遗漏了 None 的匹配。
类似 let , for和match 都必须要求完全覆盖匹配才能通过编译( 不可驳模式匹配 )。
但是对于 if let就可以这样使用
if let Some(x) some_option_value {println!({}, x);
}因为 if let 允许匹配一种模式而忽略其余的模式( 可驳模式匹配 )。
5.3 全模式列表