6.1 枚举

枚举允许我们列举所有可能的值来定义一个类型

1
2
3
4
enum IpAddsKind {
V4,
V6,
}
  • 其中V4V6称为该枚举类型的变体
  • 枚举的变体都位于对应的命名空间下,用::进行分隔
1
let four = IpAddsKind::V4;
  • 这里定义的four就是一个枚举类型

该类型也可以作为函数参数,例如

1
fn route(ip_kind: IpAddsKind) {}

枚举类型也可以作为struct的字段类型,例如

1
2
3
4
struct IpAddr {
kind: IpAddsKind,
address: String,
}

任意类型的数据也可以在枚举的变体之中,例如

1
2
3
4
5
6
7
8
9
enum IpAddsKind {
V4(u8, u8, u8, u8),
V6(String),
}

fn main() {
let home = IpAddsKind::V4(127, 0, 0, 1);
let loopback = IpAddsKind::V6(String::from("::1"));
}
  • 这里我们在V4嵌入了4个u8V6嵌入了String
  • 事实上,任意数据都可以嵌入,比如struct和另外一种enum

为枚举定义方法

struct一样,我们可以用impl为枚举类型定义方法,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
enum IpAddsKind {
V4(u8, u8, u8, u8),
V6(String),
}

impl IpAddsKind {
fn call(&self) {}
}

fn main() {
let home = IpAddsKind::V4(127, 0, 0, 1);
home.call();
}

6.2 Option枚举

Option枚举是定义在标准库里的基本方法,属于预导入模块(prelude)

  • 用于描述某个值可能存在(某个类型)或不存在的情况
  • 因为是prelude中的模块,是因不需要使用Option::

在C/C++和Python中,都有NULL / nullptr或者None这种表示空的值,但这可能会导致一些问题,因此Rust舍弃了定义空

取而代之,为了描述那些因为某种原因缺失而无效的值,Rust定义了实现该功能的概念,即枚举类型Option<T>

在标准库中,其被定义为

1
2
3
4
enum Option<T> {
Some(T),
None,
}
  • 此处T为泛型

例如

1
2
3
let some_number = Some(5);
let some_string = Some("a string");
let absent_number: Option<i32> = None;
  • 其中前2个编译器可以自动推断,最后一个需要指定类型

Option<T>Null的优势

在Rust中,Option<T>T是不同的类型,例如

1
2
3
let x: i8 = 5;
let y: Option<i8> = Some(5);
let sum = x + y; // This is wrong!
  • 第三行会报错

在Rust中,只要这个值不是Option<T>,作为T就可以放心进行操作

如果需要取得Option<T>中的值,可以做类型转换

6.3 Match: 控制流运算符

Rust中的match是一个强大的控制流运算符,允许一个值和一系列模式进行匹配,并执行对应的匹配代码

  • 这里的模式可以是字面值、变量名、通配符

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}

fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("Lucky penny!");
1
},
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
  • 每个模式匹配使用=>来表示,前后都是表达式

绑定值的模式匹配

匹配的分支可以被绑定到匹配对象的部分值

  • 因此可以从enum变体中提取值

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#[derive(Debug)]
enum UsState {
Alabama,
Alaska,
}

enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState),
}

fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("Lucky penny!");
1
},
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("State quarter from {:?}!", state);
25
},
}
}

fn main() {
let c = Coin::Quarter(UsState::Alabama);
value_in_cents(c);
}

匹配Option<T>

示例

1
2
3
4
5
6
7
8
9
10
11
12
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i ) => Some(i + 1),
}
}

fn main() {
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
}

Match匹配默认必须枚举所有的可能情况

如果只希望枚举部分,对于剩余部分可以用通配符_来指代,且放在最后一个模式中,例如

1
2
3
4
5
6
7
8
9
10
fn main() {
let x: i8 = 5;
match x {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
4 => println!("four"),
_ => ()
}
}
  • 这里的i8有256中可能的整数,因此如果不加_的话,我们需要枚举256种情况

6.4 简单控制流if let

该控制流处理的是指考虑单一匹配的情况,是match的一种语法糖

1
2
3
4
5
6
7
8
9
10
11
fn main() {
let x: i8 = 3;
match x {
1 => println!("one"),
_ => ()
}

if let 1 = x {
println!("one");
}
}
  • 这里的if let的效果和match的效果一样
  • 注意这里的1 = x的单个模式的匹配,不能写成x = 11 == x

此外,if let还可以搭配else使用,来执行match_ =>的部分,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
fn main() {
let x: i8 = 1;
match x {
1 => println!("one"),
_ => println!("other"),
}

if let 1 = x {
println!("one");
}
else {
println!("other");
}
}