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);
}
// 计数器值加 1
n += 1;
}
}
for 循环
区间
for in
结构可以遍历一个 Iterator
(迭代器)。创建迭代器的一个最简单的方法是使用区间标记 a..b
。这会生成从 a
(包含此值) 到 b
(不含此值)的,步长为 1 的 一系列值。
fn main() {
// `n` 将在每次迭代中分别取 1, 2, ..., 100
for 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)了。
```rust
for 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 match
let 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>
#### 结构体
```rust
fn 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::Bar
if 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);
}
}
}