第五章 枚举与模式匹配
定义枚举
以ip地址作为例子,举例
enum IpAddrKind {
V4,
V6, // 枚举的变体
}
let four = IpAddrKind::V4; // 创建枚举值, 但是 里面没有具体的参数值阿?
let six = IpAddrKind::V6;
将枚举作为参数传递
enum IpAddrKind {
V4,
V6,
}
fn route(ip_kind: IpAddrKind){}
fn main(){
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
route(four);
route(six);
route(IpAddrKind::V6);
}
枚举作为struct中的一个成员使用.
enum IpAddrKind {
V4,
V6,
}
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"),
};
}
将数据附加到枚举变体中
enum IpAddr {
V4(u8,u8,u8,u8), // 在变体中指定就可以向其中存储数据
V6(String),
}
fn main() {
let home = IpAddrKind::V4(127,0,0,1);
let loopback = IpAddrKind::V6(String::from("::1"));
}
优点:
- 不需要额外使用struct结构
- 每个变体可以拥有不同的类型以及关联的数据量
为枚举定义方法
与struct相似,枚举的方法也是定义在impl中
impl Message {
fn call(&self) {}
}
Option枚举类型
Option定义于标准库中.在prelude预导入模块中.
他描述了:某个值可能存在(某种类型)或者不存在的情况.为了替换NULL这个值.
RUST 中是没有NULL的.当你尝试使用非NULL值那样使用NULL值的时候,就会引起某种错误.
rust中类似NULL的概念的是 Option<T>
标准库中的定义是
enum Option<T> {
Some(T),
None,
}
他包含在prelude中,可以直接使用如下几种接口,其中T是指具体的类型. Some(T) None 都是T类型.
Option<T>
Some(T)
None
具体用法
fn main() {
let x: i8 = 5;
let y: Option<i8> = Some(5);
let sum = x + y; // 这里会报错,因为Option<i8>并不等于i8,两者并不是一个类型,所以不能够相加,想要进行计算需要将Option进行转换为i8.
}
不能将 Option(i8) 当成 i8使用, 若想按照 i8 使用, 必须先将它转换为i8.
有了Option之后, 如果一个变量的类型不是Option 那他必然是有值的,不存在空值的问题, 如果是Option类型, 则必须转换后使用.
match
允许一个值和一系列模式进行匹配,并执行匹配的模式对应的代码. match也是表达式.
模式可以是字面值,变量名 ,通配符等
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("penny");
1
}, // {}用来括住多行语句
Coin::Nickel => 5, // =>后是匹配成功后,执行的代码.
Coin::Dime => 10,
Coin::Quarter => 25,
} // 匹配成功的表达式值,会作为整个match表达式的值返回
}
fn main() {}
绑定值的模式
匹配的分支(match中的分支)可以绑定到被匹配对象(传进来的值)的部分值.
因此,可以从enum变体中提取值.
#[derive(Debug)]
enum UsState {
Alabama,
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) => { // 由于Quarter可以存储值,所以使用state存储值.这就是绑定值的匹配
println!("State quarter from {:?}!", state);
25
}
}
}
fn main() {
let c = Coin::Quarter(UsState::Alaska);
println!("{}", value_in_cents(c));
}
匹配Option值
fn main() {
let five = Some(5);
let six = plus_one(five);
let none = plus_one(None);
}
fn plus_one(x: Option<i32>) -> Option<i32>{
match x {
None => None,
Some(i) => Some(i+1),
} // 返回的是Option对象
}
match在匹配时要覆盖到所有的可能情况.比如上方的例子,x是Option的类型,其中Option中有可能有None值,需要覆盖到这种情况.
可以使用通配符 _来覆盖其余的情况,比如下面的方式
fn main() {
let v = 0u8;
match v {
1 => println!("one"),
2 => println!("three"),
3 => println!("five"),
4 => println!("seven"),
_ => (),
}
}
匹配值
fn category(x: i32) {
match x {
-1 => println!("negative"),
0 => println!("zero"),
1 => println!("positive"),
_ => println!("error"),
}
}
fn main() {
let x = 1;
category(x);
}
使用|匹配多个条件
fn category(x: i32) {
match x {
-1 | 1 => println!("true"),
0 => println!("false"),
_ => println!("error"),
}
}
fn main() {
let x = 1;
category(x);
}
使用范围作为匹配条件, .. 表示前闭后开区间, ..=表示闭区间
let x = 'X';
match x {
'a' ..= 'z' => println!("lowercase"),
'A' ..= 'Z' => println!("suppercase"),
_ => println!("something else"),
}
下划线
下划线的功能是忽略绑定到的值, 任何绑定到_的值都会被丢弃. 在模式匹配的地方, 可以用下划线来代表一个占位符.
struct P(f32, f32, f32);
fn calc(arg: P) -> f32 { // fn calc(P(x, _, y): P) -> { 改成这样也可以
let P(x, _, y) = arg;
x * x + y * y
}
fn main(){
let t = P(1.0, 2.0, 3.0);
println!("{}", calc(t));
}
下划线在绑定值之后, 就不能在使用了,因为绑定的值已经被丢弃不能适用了.
if let一个简单的控制流
只关心一种匹配而忽略其他匹配的情况.相当于只有一个 if 剩下都是else
fn main() {
let v = Some(0u8);
match v {
Some(3) => println!("three"),
_ => (),
}
if let Some(3) = v {
println!("three");
}
else {
println!("others");
}
// 上面的段代码是等价的.
}