6. Rust 枚举与模式匹配
6.1 定义枚举
枚举(Enum)是一种类型,它允许你定义一个类型可以是多个不同的变体之一。枚举的变体称为 枚举成员(Enum Member)。
rust
enum IpAddrKind {
V4,
V6,
}
创建枚举实例:
rust
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
枚举不同的变体可以包含不同的数据类型和关联数据。例如:
rust
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}
使用:
rust
#[derive(Debug)]
enum IpAddrKind {
V4(u8, u8, u8, u8),
V6(String),
}
fn main() {
let home = IpAddrKind::V4(127, 0, 0, 1);
let loopback = IpAddrKind::V6(String::from("::1"));
println!("home: {:?}", home);
println!("loopback: {:?}", loopback);
}
还可以为枚举实现方法:
rust
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
impl Message {
fn call(&self) {
// method body would be defined here
println!("call")
}
}
fn main() {
let msg = Message::Write(String::from("hello"));
let msg2 = Message::ChangeColor(0, 0, 0);
let msg3 = Message::Move { x: 0, y: 0 };
let msg4 = Message::Quit;
msg.call();
}
其中 Move
成员包含了一个匿名结构体,Write
成员包含了一个 String
,ChangeColor
成员包含了三个 i32
值。
6.2 Option 枚举
Option
是标准库中定义的一个枚举,它有两个变体:Some
和 None
。其位于预导入库中,可直接使用。
Rust 中没有 Null 值,Rust 提供了 Option<T>
来处理可能为 null
的情况。其定义如下:
rust
enum Option<T> {
Some(T),
None,
}
使用:
rust
fn main() {
let some_number = Some(5); // Some(i32)
let some_string = Some("a string"); // Some(&str)
let absent_number: Option<i32> = None; // None
}
Option<T>
和 T
是不同的类型,我们使用时必须将其转换为相同的类型。可以使用 unwrap
方法来获取 Option<T>
中的值,如果 Option<T>
是 None
,unwrap
会导致 panic。
rust
fn main() {
let some_number = Some(5);
let number = 5;
let sum = number + some_number.unwrap_or(0);
println!("sum: {}", sum);
}
6.3 match 控制流
match
是 Rust 中的一个关键字,它允许我们将一个值与一系列模式进行比较,并根据匹配的模式执行相应的代码。
rust
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
绑定值的模式:
rust
#[derive(Debug)]
enum UsState {
Alabama,
Alaska,
}
enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState),
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => 1,
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => {
println!("State quarter from {:?}", state);
25
}
}
}
fn main() {
let c = Coin::Quarter(UsState::Alaska);
println!("{}", value_in_cents(c));
}
同理,Option<T>
也可以使用 match
:
rust
fn main() {
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
println!("{:?}", six);
println!("{:?}", none);
}
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}
match
匹配必须穷举所有可能的情况,否则编译器会报错。可以使用 _
通配符来匹配所有其他情况。
rust
fn main() {
let some_u8_value = 0u8;
match some_u8_value {
1 => println!("one"),
3 => println!("three"),
5 => println!("five"),
7 => println!("seven"),
_ => (),
}
}
6.4 if let
if let
语法允许我们只匹配一个模式,而忽略其他模式。if let
语法适用于只关心一个模式的情况,而不关心其他情况。
rust
fn main() {
let some_u8_value = Some(0u8);
if let Some(3) = some_u8_value {
println!("three");
}
}
if let
表达式可以和 else
一起使用:
rust
fn main() {
let some_u8_value = Some(0u8);
if let Some(3) = some_u8_value {
println!("three");
} else {
println!("not three");
}
}
这类似于 match
语句,但是更简洁。