🎃个人专栏:
🐬 算法设计与分析:算法设计与分析_IT闫的博客-CSDN博客
🐳Java基础:Java基础_IT闫的博客-CSDN博客
🐋c语言:c语言_IT闫的博客-CSDN博客
🐟MySQL:数据结构_IT闫的博客-CSDN博客
🐠数据结构:数据结构_IT闫的博客-CSDN博客
💎C++:C++_IT闫的博客-CSDN博客
🥽C51单片机:C51单片机(STC89C516)_IT闫的博客-CSDN博客
💻基于HTML5的网页设计及应用:基于HTML5的网页设计及应用_IT闫的博客-CSDN博客
🥏python:python_IT闫的博客-CSDN博客
🐠离散数学:离散数学_IT闫的博客-CSDN博客
🥽Linux:Linux_Y小夜的博客-CSDN博客
🚝rust:Rust_Y小夜的博客-CSDN博客
欢迎收看,希望对大家有用!
目录
🎯定义枚举
🎯Option枚举
🥽类似Null概念的枚举—Option
🎯控制流运算符-match
🥽绑定值得模式:
🥽匹配Option
🥽match匹配必须穷举所有的可能
🥽通配符
🎯if let
🎯定义枚举
枚举:
允许我们列举所有可能的值来定义一个类型。
如:
定义一个
IpAddrKind
枚举来表现这个概念并列出可能的 IP 地址类型,V4
和V6
。这被称为枚举的 成员(variants):enum IpAddrKind { V4, V6, }
枚举值:
let four = IpAddrKind::V4; let six = IpAddrKind::V6;
注意枚举的成员位于其标识符的命名空间中,并使用两个冒号分开。这么设计的益处是现在
IpAddrKind::V4
和IpAddrKind::V6
都是IpAddrKind
类型的。fn route(ip_kind: IpAddrKind) {}
现在可以使用任一成员来调用这个函数:
route(IpAddrKind::V4); route(IpAddrKind::V6);
将数据附加到枚举的变体中:
enum IpAddr { V4(String), V6(String), } let home = IpAddr::V4(String::from("127.0.0.1")); let loopback = IpAddr::V6(String::from("::1"));
优点:
- 直接将数据附加到枚举的每个成员上,这样就不需要一个额外的结构体
- 每个成员可以处理不同类型和数量的数据。
如:
enum IpAddr { V4(u8, u8, u8, u8), V6(String), } let home = IpAddr::V4(127, 0, 0, 1); let loopback = IpAddr::V6(String::from("::1"));
标准库中的IpAddr
struct Ipv4Addr { // --snip-- } struct Ipv6Addr { // --snip-- } enum IpAddr { V4(Ipv4Addr), V6(Ipv6Addr), }
枚举成员中内嵌了多种多样的类型:
enum Message { Quit, Move { x: i32, y: i32 }, Write(String), ChangeColor(i32, i32, i32), }
Quit
没有关联任何数据。Move
类似结构体包含命名字段。Write
包含单独一个String
。ChangeColor
包含三个i32
。为枚举定义方法:
例子:
impl Message { fn call(&self) { // 在这里定义方法体 } } let m = Message::Write(String::from("hello")); m.call();
🎯Option枚举
Option
是标准库定义的另一个枚举。- 在Prelude(预导入模块中)
- 描述了:某个可能存在(某种类型)或不存在的情况。
Rust 并没有很多其他语言中有的空值功能。空值(Null )是一个值,它代表没有值。
- Null引用:The Billion Dollar Mistake
- Null的问题在于:当尝试像使用非Null值那样使用Null值的时候,就会引起某种错误。
- Null的概念还是有用的,因某种原因变为无效或缺失的值。
🥽类似Null概念的枚举—Option<T>
enum Option<T> { None, Some(T), }
它包括在Prelude(与导入模块)中。可直接使用:
—Option<T>
—Some(T)
—None
可以不需要
Option::
前缀来直接使用。例子:
let some_number = Some(5); let some_char = Some('e'); let absent_number: Option<i32> = None;
Rust 需要我们指定
Option
整体的类型,因为编译器只通过None
值无法推断出Some
成员保存的值的类型。这里我们告诉 Rust 希望absent_number
是Option<i32>
类型的。简而言之,因为
Option<T>
和T
(这里T
可以是任何类型)是不同的类型,编译器不允许像一个肯定有效的值那样使用Option<T>
。如:
let x: i8 = 5; let y: Option<i8> = Some(5); let sum = x + y;
会出现类型不匹配的错误。
若想使用Option<T>中的T,必须将它转化为T。
🎯控制流运算符-match
- 我们将一个值与一系列的模式相比较,并根据相匹配的模式执行相应代码。
- 模式可由字面值、变量、通配符和许多其他内容构成。
例子:
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, } }
🥽绑定值得模式:
例子:
#[derive(Debug)] // 这样可以立刻看到州的名称 enum UsState { Alabama, Alaska, // --snip-- } 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 } } }
在这些代码的匹配表达式中,我们在匹配
Coin::Quarter
成员的分支的模式中增加了一个叫做state
的变量。当匹配到Coin::Quarter
时,变量state
将会绑定 25 美分硬币所对应州的值。接着在那个分支的代码中使用state。
🥽匹配Option<T>
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
值,而不尝试执行任何操作。
🥽match匹配必须穷举所有的可能
fn plus_one(x: Option<i32>) -> Option<i32> { match x { Some(i) => Some(i + 1), } }
没有处理
None
的情况,所以这些代码会造成一个 bug
🥽通配符
let dice_roll = 9; match dice_roll { 3 => add_fancy_hat(), 7 => remove_fancy_hat(), _ => (), } fn add_fancy_hat() {} fn remove_fancy_hat() {}
如果你掷出 3 或 7 以外的值,你的回合将无事发生。
🎯if let
if let
语法获取通过等号分隔的一个模式和一个表达式。它的工作方式与match
相同,这里的表达式对应match
而模式则对应第一个分支。但是,这样会失去
match
强制要求的穷尽性检查。match
和if let
之间的选择依赖特定的环境以及增加简洁度和失去穷尽性检查的权衡取舍。let config_max = Some(3u8); if let Some(max) = config_max { println!("The maximum is configured to be {}", max); }
等价于
let config_max = Some(3u8); match config_max { Some(max) => println!("The maximum is configured to be {}", max), _ => (), }