6.1 定义枚举
枚举
枚举允许我们列举所有可能的值来定义一个类型
定义枚举
案例
IP地址:IPv4、IPv6
enum IpAddKind {
V4,
V6,
}
枚举值
let four=IpAddKind::V4;
let six=IpAddKind::V6;
将数据附加到枚举的变体中
修改前:
enum IpAddKind {
V4,
V6,
}
struct IpAddr{
kind:IpAddKind,
address:String,
}
fn main(){
let home=IpAddr{
kind:IpAddKind::V4,
address:String::from("127.0.0.1"),
};
let home=IpAddr{
kind:IpAddKind::V6,
address:String::from("::1"),
};
}
修改后:
enum IpAddKind {
V4(u8,u8,u8,u8),
V6(String),
}
fn main(){
let home=IpAddKind::V4(127,0,0,1);
let loopback=IpAddKind::V6(String::from("::1"));
}
- 优点:
- 不需要额外使用struct
- 每个变体可以拥有不同的类型以及关联的数据量
enum IpAddKind {
V4(u8,u8,u8,u8),
V6(String),
}
标准库中的 IpAddr
enum Message {
Quit,
Move{x:i32,y:i32},
Write(String),
ChangeColor(i32,i32,i32),
}
fn main(){
let q=Message::Quit;
let m=Message::Move { x: (12), y: (32) };
let w=Message::Write(String::from("Hello"));
let c=Message::ChangeColor((0), (255), (255));
}
为枚举定义方法
使用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: (32) };
let w=Message::Write(String::from("Hello"));
let c=Message::ChangeColor((0), (255), (255));
}
6.2 Option枚举
Option 枚举
- 定义于标准库中
- 在 Prelude(预导入模块) 中
- 描述了:某个值可能存在(某种类型)或不存在的情况
Rust 没有 Null
- 其它语言中:
- Null 是一个值,它表示“没有值”
- 一个变量可以处于两种状态: 空值 (null)、非空
- Null 引用: Billion Dollar Mistake
= Null 的问题在于:当你尝试像使用非 Nul 值那样使用 Nul 值的时候,就会引起某种错误 - Null 的概念还是有用的:因某种原因而变为无效或缺失的值
Rust 中类似 Null 概念的枚举 -Option
- 标准库中的定义;
enum Option<T>{
Some(T),
None,
}
- 它包含在 Prelude(预导入模块)中。可直接使用:
- Option< T >
- Some(T)
- None
fn main(){
let some_number=Some(4);
let some_string=Some("Hello");
let abstract_number:Option<i32>=None;
}
Option 比 Null 好在哪?
Option 和T是不同的类型,不可以把 Option 直接当成T
fn main(){
let x:i8=5;
let y:Option<i8>=Some(5);
let sum=x+y;
}
- 若想使用 Option 中的 T,必须将它转换为 T
6.3 强大的控制流运算符-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,
}
}
match语句也可以展开
fn value_in_cents(coin:Coin) -> u8{
match coin{
Coin::Penny =>{
println!("Penny!");
1
}
Coin::Nickel =>5,
Coin::Dime =>10,
Coin::Quarter =>25,
}
}
绑定值的模式
- 匹配的分支可以绑定到被匹配对象的部分值
- 因此,可以从 enum 变体中提取值
#[derive(Debug)]
enum UsState {
Alabma,
Alaska,
}
enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState)
}
fn value_in_cents(coin:Coin) -> u8{
match coin{
Coin::Penny =>{
println!("Penny!");
1
}
Coin::Nickel =>5,
Coin::Dime =>10,
Coin::Quarter(state) =>{
println!("State quarter from {:?}!",state);
25
},
}
}
匹配 Option
fn plus_one(x:Option<i32>)->Option<i32>{
match x {
None =>None,
Some(i)=>Some(i+1),
}
}
fn main(){
let five =Some(5);
let six=plus_one(five);
let none=plus_one(None);
}
match 匹配必须穷举所有的可能
- _通配符:替代其余没列出的值
fn main(){
let v=0;
match v {
1=>println!("one"),
2=>println!("two"),
_=>(),
}
}
if let
- 处理只关心一种匹配而忽略其它匹配的情况
- 更少的代码,更少的缩进,更少的模板代码
- 放弃了穷举的可能0
- 可以把if let 看作是 match 的语法糖
- 搭配 else
fn main(){
let v=Some(0);
// match的写法
match v {
Some(3)=>println!("three"),
_=>(),
}
// if let写法
if let Some(3)=v{
println!("three");
}
}
fn main(){
let v=Some(0);
// match的写法
match v {
Some(3)=>println!("three"),
_=>(),
}
// if let写法
if let Some(3)=v{
println!("three");
}else{
println!("others");
}
}