if-else
布尔判断条件不必用小括号包住,且每个条件后面都跟着一个代码块。if-else 条件选择是一个表达式,并且所有分支都必须返回相同的类型。
if-else
fn main() {let n = 5;if n < 0 {print!("{} is negative", n);} else if n > 0 {print!("{} is positive", n);} else {print!("{} is zero", n);}}
let-if
fn main() {let n = 5;let big_n =if n < 10 && n > -10 {println!(", and is a small number, increase ten-fold");// 这个表达式返回一个 `i32` 类型。10 * n} else {println!(", and is a big number, half the number");// 这个表达式也必须返回一个 `i32` 类型。n / 2};// ^ 不要忘记在这里加上一个分号!所有的 `let` 绑定都需要它。println!("{} -> {}", n, big_n);}
loop 循环
使用 loop 来实现无限循环。
fn main() {let mut count = 0u32;// 无限循环loop {count += 1;if count == 3 {println!("three");// 跳过这次迭代的剩下内容continue;}println!("{}", count);if count == 5 {println!("OK, that's enough");// 退出循环break;}}}
嵌套循环和标签
在处理嵌套循环的时候可以 break 或 continue 外层循环。在这类情形中,循环必须 用一些 'label(标签)来注明,并且标签必须传递给 break/continue 语句。
#![allow(unreachable_code)]fn main() {'outer: loop {println!("Entered the outer loop");'inner: loop {println!("Entered the inner loop");// 这只是中断内部的循环//break;// 这会中断外层循环break 'outer;}println!("This point will never be reached");}println!("Exited the outer loop");}
从 loop 循环中返回
若操作返回一个值,将该值放在 break 之后,它就会被 loop 表达式返回。
fn main() {let mut counter = 0;let result = loop {counter += 1;if counter == 10 {break counter * 2;}};assert_eq!(result, 20);}
while 循环
fn main() {// 计数器变量let mut n = 1;// 当 `n` 小于 101 时循环while n < 101 {if n % 15 == 0 {println!("fizzbuzz");} else if n % 3 == 0 {println!("fizz");} else if n % 5 == 0 {println!("buzz");} else {println!("{}", n);}// 计数器值加 1n += 1;}}
for 循环
区间
for in 结构可以遍历一个 Iterator(迭代器)。创建迭代器的一个最简单的方法是使用区间标记 a..b。这会生成从 a(包含此值) 到 b(不含此值)的,步长为 1 的 一系列值。
fn main() {// `n` 将在每次迭代中分别取 1, 2, ..., 100for n in 1..101 {println!("{}", n);}}
迭代器
如果没有特别指定,for 循环会对给出的集合应用 into_iter 函数,把它转换成 一个迭代器。其他的方法有 iter 和 iter_mut 函数。
iter- 在每次迭代中借用集合中的一个元素。这样集合本身不会被改变,循环之后仍可以使用。 ```rust fn main() { let names = vec![“Bob”, “Frank”, “Ferris”];for name in names.iter() {
match name {&"Ferris" => println!("There is a rustacean among us!"),_ => println!("Hello {}", name),}
} }
- `into_iter` - 会消耗集合。在每次迭代中,集合中的数据本身会被提供。一旦集合被消耗了,之后就无法再使用了,因为它已经在循环中被 “移除”(move)了。```rustfor name in names.into_iter() {match name {"Ferris" => println!("There is a rustacean among us!"),_ => println!("Hello {}", name),}}
iter_mut- 可变地(mutably)借用集合中的每个元素,从而允许集合被就地修改。for name in names.iter_mut() {*name = match name {&mut "Ferris" => "There is a rustacean among us!",_ => "Hello",}}
match 匹配
类似于其他语言的switch
match 分支必须覆盖所有可能的值。let number = 13;match number {// 匹配单个值1 => println!("One!"),// 匹配多个值2 | 3 | 5 | 7 | 11 => println!("This is a prime"),// 匹配一个闭区间范围13..=19 => println!("A teen"),// 处理其他情况_ => println!("Ain't special"),}
let matchlet boolean = true;// match 也是一个表达式let binary = match boolean {// match 分支必须覆盖所有可能的值false => 0,true => 1,// 试一试 ^ 将其中一条分支注释掉};
解构
元组
```rust fn main() { let pair = (0, -2); // match 可以解构一个元组 match pair {
} }// 解构出第二个值(0, y) => println!("First is `0` and `y` is `{:?}`", y),(x, 0) => println!("`x` is `{:?}` and last is `0`", x),_ => println!("It doesn't matter what they are"),// `_` 表示不将值绑定到变量
<a name="E4Doa"></a>#### 枚举```rust// 需要 `allow` 来消除警告,因为只使用了枚举类型的一种取值。#[allow(dead_code)]enum Color {// 这三个取值仅由它们的名字(而非类型)来指定。Red,Blue,Green,// 这些则把 `u32` 元组赋予不同的名字,以色彩模型命名。RGB(u32, u32, u32),}fn main() {let color = Color::RGB(122, 17, 40);println!("What color is it?");// 可以使用 `match` 来解构 `enum`。match color {Color::Red => println!("The color is Red!"),Color::Blue => println!("The color is Blue!"),Color::Green => println!("The color is Green!"),Color::RGB(r, g, b) =>println!("Red: {}, green: {}, and blue: {}!", r, g, b),// 不需要其它分支,因为所有的情形都已覆盖}}
指针和引用
对指针来说,解构(destructure)和解引用(dereference)要区分开,因为这两者的概念 是不同的。
- 解引用使用
* 解构使用
&、ref、和ref mut``rust fn main() { // 获得一个i32类型的引用。&` 表示取引用。 let reference = &4;match reference {
// 译注:因此可用 `val` 表示被 `reference` 引用的值 4。&val => println!("Got a value via destructuring: {:?}", val),
}
// 如果不想用
&,需要在匹配前解引用。 match *reference {val => println!("Got a value via dereferencing: {:?}", val),
}
// 如果一开始就不用引用,会怎样?
reference是一个&类型,因为赋值语句 // 的右边已经是一个引用。但下面这个不是引用,因为右边不是。 let _not_a_reference = 3;// Rust 对这种情况提供了
ref。它更改了赋值行为,从而可以对具体值创建引用。 // 下面这行将得到一个引用。 let ref _is_a_reference = 3;// 相应地,定义两个非引用的变量,通过
ref和ref mut仍可取得其引用。 let value = 5; let mut mut_value = 6;// 使用
ref关键字来创建引用。 // 译注:下面的 r 是&i32类型,它像i32一样可以直接打印,因此用法上 // 似乎看不出什么区别。但读者可以把println!中的r改成*r,仍然能 // 正常运行。前面例子中的println!里就不能是*val,因为不能对整数解 // 引用。 match value {ref r => println!("Got a reference to a value: {:?}", r),
}
// 类似地使用
ref mut。 match mut_value {ref mut m => {// 已经获得了 `mut_value` 的引用,先要解引用,才能改变它的值。*m += 10;println!("We added 10. `mut_value`: {:?}", m);},
} }
<a name="d8MPv"></a>#### 结构体```rustfn main() {struct Foo { x: (u32, u32), y: u32 }// 解构结构体的成员let foo = Foo { x: (1, 2), y: 3 };let Foo { x: (a, b), y } = foo;println!("a = {}, b = {}, y = {} ", a, b, y);// 可以解构结构体并重命名变量,成员顺序并不重要let Foo { y: i, x: j } = foo;println!("i = {:?}, j = {:?}", i, j);// 也可以忽略某些变量let Foo { y, .. } = foo;println!("y = {}", y);// 这将得到一个错误:模式中没有提及 `x` 字段// let Foo { y } = foo;}
守卫
可以加上 match 守卫(guard) 来过滤分支。
fn main() {let pair = (2, -2);println!("Tell me about {:?}", pair);match pair {(x, y) if x == y => println!("These are twins"),// ^ `if` 条件部分是一个守卫(x, y) if x + y == 0 => println!("Antimatter, kaboom!"),(x, _) if x % 2 == 1 => println!("The first one is odd"),_ => println!("No correlation..."),}}
绑定
match 中间接地访问一个变量,需要重新绑定。需要用到 @ 字符
fn main() {let age = 11u32;match age {0 => println!("I'm not born yet I guess"),// 在 1 ... 12 分支中绑定匹配值到 `n` 。现在年龄就可以读取了。n @ 1 ... 12 => println!("I'm a child of age {:?}", n),// 不符合上面的范围。返回结果。n => println!("I'm an old person of age {:?}", n),}}
绑定 Option 等:
fn main() {let age = 11u32;match age {0 => println!("I'm not born yet I guess"),// 在 1 ... 12 分支中绑定匹配值到 `n` 。现在年龄就可以读取了。n @ 1 ... 12 => println!("I'm a child of age {:?}", n),// 不符合上面的范围。返回结果。n => println!("I'm an old person of age {:?}", n),}}
if let
用 match 匹配枚举不是很优雅:
fn main() {let optional = Some(7);match optional {Some(i) => {println!("This is a really long string and `{:?}`", i);},_ => {},// ^ 必须有,因为 `match` 需要覆盖全部情况};}
使用 if let 后:
fn main() {let number = Some(7);let letter: Option<i32> = None;// `if let` 结构读作:若 `let` 将 `number` 解构成 `Some(i)`,则执行// 语句块(`{}`)if let Some(i) = number {println!("Matched {:?}!", i);}// 如果要指明失败情形,就使用 else:if let Some(i) = letter {println!("Matched {:?}!", i);} else {// 解构失败。切换到失败情形。println!("Didn't match a number. Let's go with a letter!");};}
匹配枚举值
enum Foo {Bar,Qux(u32)}fn main() {// 创建变量let a = Foo::Bar;let c = Foo::Qux(100);// 变量 a 匹配到了 Foo::Barif let Foo::Bar = a {println!("a is foobar");}// 变量 c 匹配到了 Foo::Qux,它带有一个值,就和上面例子中的 Some() 类似。if let Foo::Qux(value) = c {println!("c is {}", value);}}
while let
fn main() {// 将 `optional` 设为 `Option<i32>` 类型let mut optional = Some(0);// 这读作:当 `let` 将 `optional` 解构成 `Some(i)` 时,就// 执行语句块(`{}`)。否则就 `break`。while let Some(i) = optional {if i > 9 {println!("Greater than 9, quit!");optional = None;} else {println!("`i` is `{:?}`. Try again.", i);optional = Some(i + 1);}}}
