当前位置:网站首页>Rust 中的枚举和控制流运算
Rust 中的枚举和控制流运算
2022-06-27 17:58:00 【用户3147702】
1. 引言
枚举类型对于 Java 程序员来说不会陌生,它是列举常量成员的非常好用的工具。在 rust 中也同样如此,并且在 rust 中,枚举类型比其他语言中更为常用,尤其是 Option、Result 等语言自身定义的枚举类型,为 rust 本身添加了非常强大而独特的语法特性。
2. 枚举类型
与 java 语言枚举中关注枚举的类型和值不同,rust 中的枚举专注于类型,枚举成员本身是不对应具体的值的。
2.1 枚举类型的定义
例如,下面的枚举类型定义了 IPv4 和 IPv6 两个成员:
enum IpAddrKind {
V4,
V6,
}
fn main() {
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
route(IpAddrKind::V4);
route(IpAddrKind::V6);
}
fn route(ip_kind: IpAddrKind) {}2.2 枚举类型的数据
上面的例子中,定义了一个枚举类型,并且创建了相应类型的的变量。
但我们往往不仅希望变量体现出具体的类型,还希望变量具备具体的值。
此时我们可以将枚举类型与具体的值再进行一层封装,从而得到一个同时包含类型和值的结构体。
fn main() {
enum IpAddrKind {
V4,
V6,
}
struct IpAddr {
kind: IpAddrKind,
address: String,
}
let home = IpAddr {
kind: IpAddrKind::V4,
address: String::from("127.0.0.1"),
};
let loopback = IpAddr {
kind: IpAddrKind::V6,
address: String::from("::1"),
};
}进一步,我们可以通过 rust 的语法糖来简化上述结构体的定义:
fn main() {
enum IpAddr {
V4(String),
V6(String),
}
let home = IpAddr::V4(String::from("127.0.0.1"));
let loopback = IpAddr::V6(String::from("::1"));
}这样一来,数据被直接附加在了枚举类型上。相较于上面通过结构体定义的复合类型,枚举类型上直接附加数据还可以定义不同类型的数据:
fn main() {
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}
let home = IpAddr::V4(127, 0, 0, 1);
let loopback = IpAddr::V6(String::from("::1"));
}3. 特殊的枚举类型 Option
Option 是 rust 标准库定义的一个枚举。Option 的存在,尝试去解决令无数软件开发工程师抓狂的空指针、空引用问题。
3.1 Option 的定义
Option 的定义如下:
enum Option<T> {
None,
Some(T),
}看起来非常简单,如果一个函数或是表达式要返回一个 T 类型的数据,并且 T 类型的数据有可能为空。那么用 Option 封装将会是一个更好的选择。因为 T 类型的数据如果为空值,而使用者忽略了这一情况,将会产生程序的 panic,这通常是我们不希望看到的。
3.2 Option 变量的创建
可以这样获得一个 Option 的数据:
let x: Option<u32> = Some(2);
assert_eq!(x.is_some(), true);
let x: Option<u32> = None;
assert_eq!(x.is_some(), false);
let x: Option<u32> = None;
assert_eq!(x.is_none(), true);一旦一个返回值被 Option 封装起来,使用者就必须处理值为 None 的情况,这一显式的处理,避免了意外的空引用、空指针的产生。
3.3 Option 数据的获取
要想获取 Option 中的实际数据,可以通过很多种方法,此处介绍 unwrap 方法。
1. unwrap 方法
unwarp 方法需要保证有值,一旦值为 None,那么就会让程序 panic。
// 如果值为 None,则 unwrap 将导致 panic
let x = Some("air");
assert_eq!(x.unwrap(), "air");2. unwrap_or 方法
与 unwrap 方法不同,unwrap_or 方法允许传递一个参数,当值为 None 时,则以这个参数作为返回值。
assert_eq!(Some("car").unwrap_or("bike"), "car");
assert_eq!(None.unwrap_or("bike"), "bike");3. unwrap_or_else 方法
unwrap_or 方法让我们能够提供默认的返回值,但更为高级的是 unwrap_or_else 方法,它允许我们创建一个函数或表达式来决定当值为 None 时返回什么。
let vec = vec![1,2,3];
let a: &i32 = vec.get(4).unwrap_or_else(||{
vec.get(0)
});4. 控制流 match
正如在 java 语言中,枚举类型搭配 switch-case 可以让代码显得十分简洁易于维护。在 Rust 中,通过强大的控制流运算符 match 搭配枚举也同样可以实现类似的效果。
4.1 match 的使用
下面就是一个 match 控制流的示例:
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("Lucky penny!");
1
}
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}4.2 match 获取枚举值
对于某个枚举拥有他的枚举数据值时,也可以进行 match:
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
}
}
}4.3 Option 与 match 匹配
有了上述 4.2 节的示例,我们就可以来处理 Option 类型的数据了:
fn plus_one(x: Option<i32>) -> Option<i32> {
match x {
None => None,
Some(i) => Some(i + 1),
}
}
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);这个示例定义了一个函数,它获取一个 Option<i32> ,如果其中含有一个值,将其加一。如果其中没有值,函数应该返回 None 值,而不尝试执行任何操作。
4.4 通配模式
需要注意的是,如果要使用 match 控制流,枚举类型包含的每一个类型都必须要出现在 match 块中。
但有时,我们希望有一种模式可以用来代替所有其他情况,类似于其他语言 switch 语句中的 default 关键字,在 Rust 中,同样是支持这一特性的,那就是 _ 占位符:
let dice_roll = 9;
match dice_roll {
3 => add_fancy_hat(),
7 => remove_fancy_hat(),
_ => (),
}
fn add_fancy_hat() {}
fn remove_fancy_hat() {}5. if let 控制流
很多时候,我们只想简洁地获取一个枚举对应的值或表达式,通过 match 表达式往往会显得太过复杂。此时,if let 可能会是更好的选择,例如:
#[derive(Debug)]
enum UsState {
Alabama,
Alaska,
// --snip--
}
enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState),
}
fn main() {
let coin = Coin::Penny;
let mut count = 0;
if let Coin::Quarter(state) = coin {
println!("State quarter from {:?}!", state);
} else {
count += 1;
}
}边栏推荐
猜你喜欢

Bit.Store:熊市漫漫,稳定Staking产品或成主旋律

Redis 原理 - String

MySQL初学者福利

New Zhongda chongci scientific and Technological Innovation Board: annual revenue of 284million and proposed fund-raising of 557million

今晚战码先锋润和赛道第2期直播丨如何参与OpenHarmony代码贡献

如何利用 RPA 实现自动化获客?

The Fifth Discipline: the art and practice of learning organization

从感知机到前馈神经网络的数学推导

《第五项修炼》(The Fifth Discipline):学习型组织的艺术与实践

Online text batch inversion by line tool
随机推荐
What is ssr/ssg/isr? How do I host them on AWS?
Leetcode 989. 数组形式的整数加法(简单)
UE4实现长按功能
openssl客户端编程:一个不起眼的函数导致的SSL会话失败问题
GIS遥感R语言学习看这里
拥抱云原生:江苏移动订单中心实践
OpenSSL client programming: SSL session failure caused by an obscure function
国际数字经济学院、华南理工 | Unified BERT for Few-shot Natural Language Understanding(用于小样本自然语言理解的统一BERT)
从感知机到前馈神经网络的数学推导
Is it safe to buy stocks and open an account on the account opening link of the securities manager? Ask the great God for help
今晚战码先锋润和赛道第2期直播丨如何参与OpenHarmony代码贡献
深度学习和神经网络的介绍
Bit. Store: long bear market, stable stacking products may become the main theme
Photoshop layer related concepts layercomp layers move rotate duplicate layer compound layer
Kotlin微信支付回调后界面卡死并抛出UIPageFragmentActivity WindowLeaked
Labelimg usage guide
Buzzer experiment based on stm32f103zet6 library function
Determine whether a variable is an array or an object?
带你认识图数据库性能和场景测试利器LDBC SNB
Batch insert data using MySQL bulkloader