枚举与模式匹配
枚举
枚举允许列举所有可能的值来定义一个类型。与 Cpp 类似。
将数据附加到枚举的变体中。
- 不再需要额外使用 struct。
- 每个变体可以拥有不同的类型以及关联的数据量。
enum IpAddr{ V4(String), V6(String), } enum IpAddr{ V4(u8, u8, u8, u8), V6(String), }
为枚举定义方法
- 可以使用 impl 为枚举定义方法。
enum Message {
Quit, // 未关联任何数据
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
impl Message {
fn call(&self) {}
}
fn main() {
let q = Message::Quit;
let m = Message::Move { x: 12, y: 24 };
let w = Message::Write(String::from("Hello"));
let c = Message::ChangeColor(0, 255, 255);
m.call()
}
Option 枚举
- 定义于标准库中。
- 在 Prelude(预导入模块)中。
- 描述了某个值可能存在(某种类型)或不存在的情况。
Rust 没有 Null
Null 的问题在于:当尝试像使用非 Null 值那样使用 Null 值的时候,就会引起某种错误。
- 但是 Null 概念为了表示因某种原因而变为无效或缺失的值还是必须的,因此 Rust 提供了 Option。
Rust 中类似 Null 概念的枚举-
Option<T>
。- 它包含在预导入模块中,可以直接使用。
enum Option<T>{ some(T), None, } let some_number = Some(5); let some_string = Some("A String"); let absent_number: Option<i32> = None; // None 类型不会自动推导需要指定
这样设计的优势在于
Option<T>
和 T 是不同的类型,不可以把Option<T>
直接当成 T 来使用。- 若想使用
Option<T>
中的 T,必须将它转换为 T。
let x: i8 = 5; let y: Option<i8> = Some(5); let sum = x + y; // error,必须强转后才能使用
- 若想使用
控制流运算符 - match
match 允许一个值与一系列模式进行匹配,并执行匹配的模式对应代码。
模式可以是字面值、变量名、通配符等。
enum Coin { Penny, Nickel, Dime, Quarter, } fn test_match(coin: Coin) -> u8 { match coin { Coin::Penny => { println!("Penny"); 1 } Coin::Nickel => 5, Coin::Dime => 10, Coin::Quarter => 25, } }
绑定值的模式,匹配的分支可以绑定到被匹配对象的部分值。
- 因此,可以从 enum 变体中提取值。
#[derive(Debug)] enum UsState { Alabama, Alaska, } enum Coin { Penny, Nickel, Dime, Quarter(UsState), } fn test_match(coin: Coin) -> u8 { match coin { Coin::Penny => { println!("Penny"); 1 } Coin::Nickel => 5, Coin::Dime => 10, Coin::Quarter(state) => { // 绑定 state 值进行模式匹配 println!("State quarter from {:?}!", state); 25 } } }
模式匹配
Option<T>
。fn call() { let five = Some(5); let six = plus_one(five); let none = plus_one(None); } fn plus_one(x: Option<i32>) -> Option<i32> { match x { None => None, Some(i) => Some(i + 1), } }
match 匹配必须穷举所有的可能,不关心的分支可以用
_
通配符。let v = 0_u8; match v { 1 => println!("one"), 3 => println!("three"), _ => (), }
if let
处理只关心一种匹配而忽略其他分支的情况。
- 更少的代码,更少的缩进,更少的模版代码。
- 放弃了穷举的可能。
let v = Some(0_u8); match v { Some(3) => println!("three"), _ => (), } if let Some(3) = v { println!("three"); }
搭配 else 进行使用。
if let Some(3) = v { println!("three"); } else { println!("other"); }