我们在Java和C等语言中也使用过枚举,现在让我们看一下Rust的枚举,这里我们使用Rust的枚举定义IP地址分类:IPV4/IPV6
enum IpAddrKind {
V4,
V6
}
下面看一下如何使用枚举值:
#[derive(Debug)]
enum IpAddrKind {
V4,
V6
}
fn main() {
let ipv4 = IpAddrKind::V4;
let ipv6 = IpAddrKind::V6;
println!("{:?} - {:?}", ipv4, ipv6); // V4 - V6
}
接下看一下如何函数参数中使用枚举值:
fn route(ip_type: IpAddrKind) {}
// 使用
route(IpAddrKind::V4);
route(IpAddrKind::V6);
现在IP枚举类型可以表示但是无法存储IP地址数据,这里我们可以使用结构体配合一起使用:
#[derive(Debug)]
enum IpAddrKind {
V4,
V6
}
#[derive(Debug)]
struct IpAddr {
kind: IpAddrKind,
address: String,
}
fn main() {
let home = IpAddr { kind: IpAddrKind::V4, address: String::from("127.0.0.1") };
let loopback = IpAddr { kind: IpAddrKind::V6, address: String::from("::1") };
}
其实Rust枚举是允许将其关联的数据嵌入枚举变体内,下面看例子:
#[derive(Debug)]
enum IpAddr {
V4(String),
V6(String),
}
fn main() {
let home = IpAddr::V4(String::from("127.0.0.1"));
let loopback = IpAddr::V6(String::from("::1"));
}
其实Rust枚举可以嵌套各种各样的数据类型,下面举个例子:
#[derive(Debug)]
struct Data {}
#[derive(Debug)]
enum Message {
Quit, // 空结构体
Move { x: i32, y: i32 }, // 匿名结构体
Write(String), // 元组结构体
Color(i32, i32, i32), // 元组结构体
Data, // 结构体
}
其实这些数据类型都是看作是一个个结构体。
Option
枚举是一个非常常见且实用的枚举。Option
类型描述了一种值可能不存在的情况。不存在就会出现空值的情况,空值可能会触发程序错误。Rust中没有空置,但是我们可以使用Option
,先看一下标准库中的定义:
pub enum Option<T> {
/// No value.
None,
/// Some value of type `T`.
Some(#[stable(feature = "rust1", since = "1.0.0")] T),
}
Option在标准库中存在例子的,下面看一下例子:
let some_number = Some(5);
let some_string = Some("a string");
let absent_number: Option<i32> = None;
下面列出一些常用方法,参考来源:Rust - Option 常用方法
方法 | 解释 | 方法 | 解释 |
---|---|---|---|
is_some/is_none | 若是Some 则返回true /若是None 则返回true | inspect | 若是Some(v) 则调用 f(&v) ,随后返回Self |
is_some_and | 若Some 并且f 函数返回true | ok_or | 由Option 变为Resuilt ,若是None 则返回Err(err) |
unwrap | 若是Some(v) ,则返回v ,如果None ,则直接panic | ok_or_else | 和ok_or 一样,无非是err 值变为err() 的返回值 |
expect | 和unwrap 一样,只不过None 后可以带 msg 数据 | as_deref | 将Option 转为Deref 解引用后的D 值Option |
unwrap_or | 若是Some(v) ,则返回v ,如果None ,则返回default | as_deref_mut | 和as_deref 一样,不同的是 是DerefMut 解引用后的值 |
unwrap_or_else | 若是Some(v) ,则返回v ,如果None ,则返回f 函数提供的返回值 | and | self 和optb 若都是Some ,则返回optb ,否则返回None |
unwrap_or_default | 若是Some(v) ,则返回v ,如果None ,则返回T::default 函数的返回值 | and_then | 和and 一样 , 不同的是optb 是f() 函数的返回值 |
map | 将Option 类型 通过f 函数转为 Option 类型 | filter | 若是None ,则直接返回None ,若是Some(v) ,则判断predicate(v) 的返回值;若predicate 返回ture ,则返回Some(v) ,否则返回None |
map_or | 和map 一样,不同的是 若是 None 则返回default ;所以 map_or 返回的不是 Option 而是U ,因为它一定存在返回值 | or | self 和optb 都是None ,则返回None ;self 和optb 其中一个是Some ,则返回是Some 的那一个;self 和optb 都是Some ,优先返回self |
map_or_else | or_else | 和or 一样 , 不同的是 optb 是f() 函数的返回值 | |
xor | self 和optb 其中一个是Some ,则返回是Some 的那一个,self 和optb 一样,则返回None | get_or_insert_with | 和get_or_insert 一样,不同的是插入值是f() 函数的返回值 |
insert | 插入一个新值,旧值被删除;注意返回值是插入后的可变借用,而非是旧值 | take | 取出值,在其位置留下 None |
get_or_insert | 若self 是None ,则可以插入值,并返回插入后的可变借用;若self 是Some(v) ,则无法插入,并返回v 的可变借用 | replace | 插入新值,返回旧值 |
contains | 若Some(v) 中的v==x , 则返回true | zip | 若self 和other 都是Some ,则返回 Option<(T,U)> ,其他情况则都返回None |
zip_with | 若self 和other 都是Some ,则返回 Some(f(T,U)) ,也就是返回f() 函数的返回值;其他情况则都返回 None | flatten | 将Option 转换为 Option |
Rust中有一个异常强大的控制流程运算符:match
,它允许将一个值与一系列的模式相比较,并根据匹配的模式执行相应代码。模式可由字面量、变量名、通配符和许多其他东西组成。
这里可以将match看成一个增强版的switch!
下面看一个例子:
enum Week {
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
fn week_to_str(week: Week) -> u32 {
match week {
Week::Monday => 1,
Week::Tuesday => 2,
Week::Wednesday => 3,
Week::Thursday => 4,
Week::Friday => 5,
Week::Saturday => 6,
Week::Sunday => 7,
}
}
其实很简单类似switch的写法,下面在展示几个写法, 直接上例子:
// 判断是否是工作日
fn is_work_day(week: Week) -> bool {
match week {
Week::Saturday | Week::Sunday => false, // 如果是周六和周日 不是工作日返回false
_ => true, // 其他可以不做判断直接返回true
}
}
接着我们在看一个Option和match之间的配合,直接看例子:
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
Some(data) => Some(data + 1),
_ => None
}
}
// 这里可以使用我们上面的Option的map方法进行简化写法。
fn plus_one(x: Option<i32>) -> Option<i32> {
x.map(|data| data + 1) // map函数给我们做了上面的步骤
}
if let
能让我们通过一种不那么繁琐的语法结合使用if和let,并处理那些只关心某一种匹配而忽略其他匹配的情况。
let some_value = Some(9);
match some_value {
Some(9) => println!("Ok"),
_ => (),
}
上面的例子中,其实我们只关心当some_value
的值时9
的时候,但是上面的代码写的就比较啰嗦,下面我们使用if let
优化下:
if let Some(data) = some_value {
println!("Ok")
};
if let
可以看成是match
的语法糖。它只在值满足某一特定的情况时运行代码,而忽略其他所有的可能性。
更多的用法可以看:通过例子学习Rust的match
这部分内容在18章的时候会详细介绍,这里先有一个大概的了解,下一章见!