枚举的定义
枚举可以是不同的类型
enum ChatKind {
OneToOne, // 等同于空结构体,或者叫类单元结构体
GroupChat { conversation_name: String, owner_id: i64 }, // 等同于自定义结构体
P2PChat(i64, i64), // 等同于元组结构体
TopicChat(String), // 等同于元组结构体
}
方法实现与模式匹配
- 枚举类型常与
match语句一起使用 -是一个通配符,表示无任何匹配的情况
impl ChatKind {
fn print(&self) {
match self {
ChatKind::OneToOne => {
println!("这个一个私聊")
}
ChatKind::GroupChat{conversation_name, owner_id} => {
println!("群名={}, 群主ID={}", conversation_name, owner_id)
}
ChatKind::P2PChat(from, to) => {
println!("{}发给{}的p2p消息", from, to)
}
ChatKind::TopicChat(topic) => {
println!("{}, 该话题正聊得火爆", topic)
}
_ => { println!("没有匹配到的枚举类型") }
}
}
}
创建枚举与方法调用
fn main() {
let single = ChatKind::OneToOne;
single.print();
let group = ChatKind::GroupChat {
conversation_name: "Rust学习群".to_string(),
owner_id: 112233,
};
group.print();
let p2p = ChatKind::P2PChat(112233, 445566);
p2p.print();
let topic = ChatKind::TopicChat("户外爬山推荐".to_string());
topic.print()
}
Option官方枚举
Option是标准库定义的一个枚举
#[derive(Copy, Eq, Debug, Hash)]
#[rustc_diagnostic_item = "Option"]
#[lang = "Option"]
#[stable(feature = "rust1", since = "1.0.0")]
#[allow(clippy::derived_hash_with_manual_eq)] // PartialEq is manually implemented equivalently
pub enum Option<T> {
/// No value.
#[lang = "None"]
#[stable(feature = "rust1", since = "1.0.0")]
None,
/// Some value of type `T`.
#[lang = "Some"]
#[stable(feature = "rust1", since = "1.0.0")]
Some(#[stable(feature = "rust1", since = "1.0.0")] T),
}
使用方式
- 要使用枚举里携带的值就要用
match匹配 - 赋值为None必须为参数申明Option类型和泛型类型
match可以和let一起使用
fn main() {
let one = Some(1);
let zero: Option<i32> = None;
let two = 2;
let one_val = match one {
None => { 0 }
Some(val) => { val }
};
let three = one_val + two;
println!("相加={}", three)
}
4.match可以和if let一起使用
n main() {
if let Some(val) = plus_add(Some(1), Some(2)){
println!("返回值不为空 = {}",val)
}else {
println!("返回值为空")
}
}
fn plus_add(x: Option<i32>, y: Option<i32>) -> Option<i32> {
let x_val = match x {
None => { 0 }
Some(val) => { val }
};
let y_val = match y {
None => { 0 }
Some(val) => { val }
};
if x_val + y_val == 0 {
return None;
}
return Some(x_val + y_val);
}
unwarp
unwrap 方法非常直接,当调用它时,它会尝试拆包 Option 或 Result,返回其中包含的值。如果拆包失败(即 Option 是 None 或 Result 是 Err),程序会立即崩溃并抛出一个 panic。
fn main() {
let some_value = Some(10);
let none_value: Option<i32> = None;
let value = some_value.unwrap();
println!("{}", value); // 输出: 10
// 下面这行代码会导致程序 panic,因为 `none_value` 是 `None`
// let value = none_value.unwrap();
}
因为 unwrap 可能导致程序崩溃,通常建议使用更安全的方法来处理 Option,例如:
-
unwrap_or:在Option是None时提供一个默认值。 -
unwrap_or_else:在Option是None时执行一个闭包。 -
expect:类似于unwrap,但可以提供自定义的 panic 信息。 -
match模式匹配:使用match或者if let来处理Option。
fn main() {
let some_value = Some(10);
let none_value: Option<i32> = None;
// 使用 unwrap_or 提供默认值
let value = some_value.unwrap_or(0);
println!("{}", value); // 输出: 10
let value = none_value.unwrap_or(0);
println!("{}", value); // 输出: 0
// 使用 expect 提供自定义 panic 信息
let value = some_value.expect("Should have a value");
println!("{}", value); // 输出: 10
// 下面这行代码会导致程序 panic,并输出 Should have a value
/*let value = none_value.expect("Should have a value");
println!("{}", value);*/
// 模式匹配
match some_value {
Some(val) => println!("Value is: {}", val),
None => println!("Value is missing"),
}
}
and_then
定义
impl<T> Option<T> {
pub fn and_then<U, F>(self, f: F) -> Option<U>
where
F: FnOnce(T) -> Option<U>,
{
// method implementation
}
}
and_then 接受一个闭包作为参数,该闭包对 Option 包含的值进行操作并返回一个新的 Option。如果原 Option 是 None,则直接返回 None,否则返回闭包的结果。可以方便地处理包含 Option 类型逻辑的链式操作。
fn step1(x: i32) -> Option<i32> { // 接收一个大于0的数并加1,否则返回None
if x > 0 {
Some(x + 1)
} else {
None
}
}
fn step2(x: i32) -> Option<i32> { // 接收一个偶数并除以2,否则返回None
if x % 2 == 0 {
Some(x / 2)
} else {
None
}
}
fn main() {
let result = Some(4)
.and_then(step1);
println!("{:?}", result); // 输出: Some(5)
let result = Some(4)
.and_then(step1)
.and_then(step2);
println!("{:?}", result); // 输出: None
}
map
定义
impl<T> Option<T> {
pub fn map<U, F>(self, f: F) -> Option<U>
where
F: FnOnce(T) -> U,
{
// method implementation
}
}
如果 Option 是 Some(T) 类型,则应用提供的闭包将 T 转换为一个新的值 U 并返回 Some(U)。如果 Option 是 None,则直接返回 None。
#[derive(Debug)]
struct User {
name: String,
age: u32,
}
fn main() {
let some_option = Some(2);
let result = some_option.map(|x| x + 3);
println!("{:?}", result); // 输出: Some(5)
let none_option: Option<i32> = None;
let result = none_option.map(|x| x + 3);
println!("{:?}", result); // 输出: None
let user_option = Some(User { name: "Alice".to_string(), age: 30 });
let name_option = user_option.map(|user| user.name);
println!("{:?}", name_option); // 输出: Some("Alice")
}
is_some_and
impl<T> Option<T> {
pub fn is_some_and<F>(&self, f: F) -> bool
where
F: FnOnce(&T) -> bool,
{
// method implementation
}
}
用于检查 Option 是否包含某个值并且这个值满足指定的条件。这个方法可用于简化需要同时检查值的存在性和条件的代码逻辑,使代码更加简洁和易读。
#[derive(Debug)]
struct User {
name: String,
age: u32,
}
fn main() {
let some_option = Some(4);
let result = some_option.is_some_and(|x| x > 2);
println!("{}", result); // 输出: true
let result = some_option.is_some_and(|x| x < 2);
println!("{}", result); // 输出: false
let none_option: Option<i32> = None;
let result = none_option.is_some_and(|x| x > 2);
println!("{}", result); // 输出: false
let user_option = Some(User { name: "Alice".to_string(), age: 30 });
// 检查 user_option 是否包含一个年龄大于20的用户
let is_age_greater_than_20 = user_option.is_some_and(|user| user.age > 20);
println!("{}", is_age_greater_than_20); // 输出: true
let user_option = Some(User { name: "Alice".to_string(), age: 30 });
// 检查 user_option 是否包含一个名字是 "Bob" 的用户
let is_name_bob = user_option.is_some_and(|user| user.name == "Bob");
println!("{}", is_name_bob); // 输出: false
}
结合?运算符
Option 类型和 ? 运算符(又称作 “question mark”)可以结合使用以简化错误处理和短路返回机制。? 运算符不仅可以用于 Result 类型,同样也可以用于 Option 类型。
例如当一个函数返回 Option 类型并想要在某个点快速返回 None,则可以使用? 运算符避免繁琐的匹配模式,并使代码更加简洁和可读。
如果 Option 类型?不为None则返回实际值。
fn find_and_double(input: Option<&str>) -> Option<i32> {
let input_str = input?; // 如果input为None,则直接返回None
let number = extract_number(input_str)?; // // 如果函数返回值为None,则直接返回None
Some(number * 2)
}
fn extract_number(input: &str) -> Option<i32> {
input.trim().parse::<i32>().ok()
}
fn main() {
let valid_input = Some("42");
let invalid_input = Some("not a number");
let none_input: Option<&str> = None;
println!("{:?}", find_and_double(valid_input)); // 输出: Some(84)
println!("{:?}", find_and_double(invalid_input)); // 输出: None
println!("{:?}", find_and_double(none_input)); // 输出: None
}
ok_or_else
允许将一个 Option 转换为 Result,并在 Option 为 None 的时候提供一个默认的错误值(由一个闭包或函数生成)。
fn main() {
// 一个 Option 中包含了一个值
let some_value: Option<i32> = Some(10);
let result: Result<i32, String> = some_value.ok_or_else(|| "This is an error".to_string());
match result {
Ok(val) => println!("Got the value: {}", val), // Got the value: 10
Err(err) => println!("Error: {}", err),
}
// 一个 Option 中不包含任何值
let none_value: Option<i32> = None;
let result: Result<i32, String> = none_value.ok_or_else(|| "This is an error".to_string());
match result {
Ok(val) => println!("Got the value: {}", val),
Err(err) => println!("Error: {}", err), // Error: This is an error
}
}