枚举
枚举类型通常用于属于同一个类型但不同的值。例如IP地址分为IPV4和IPV6。
enum IpAddrKind {
V4,
V6,
}声明上面的枚举所列出的可能的IP地址的种类,就是枚举变体(variant)。
枚举有多个用法,其中一个用法跟其它语言中的枚举一样,通常是为了程序可读性而为一个类型的所有可能值取一个更加直观的名称。
可以直接如下使用:
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;枚举值具有相同的类型,所以可以使用同一个类型的参数来接收所有同一枚举的值。
在Rust中的枚举有一个最重要的特点,每个变体可以拥有不同类型和数量的关联数据。先看不使用这一点的IP地址的存储
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");
};如果我们将关联的数据嵌入枚举变体内,那么上面的代码可以变更为:
enum IpAddr {
V4(String),
V6(String),
}
let home = IpAddr::V4(String::from("127.0.0.1"));
let loopbck = 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"));通过上面的学习,我们了解了在Rust中枚举的一个重要特点,通过枚举可以对不同的类型的数据进行同一的处理。我们可以用一个枚举类型来接收实际上类型并不相同但含义相同的数据。
枚举与结构体一样,可以使用impl关键字为其实现方法,例如一个Message的枚举:
impl Message {
fn call(&self) {
}
}接下来来看一下Rust中比较重要的几个枚举Option
Option枚举
我们知道很多语言都支持空值(NULL), 因为空值方便系统的实现。但是空值的存在有一个问题,那就是如果尝试像使用非空值一样使用空值,就会触发某种程度上的错误。
空值本身的概念是有意义的:它代表因为某种原因无效或者缺失的值。我们编写代码的时候也需要区分值不存在的情况,但是我们不希望空值本身存在,因为可能会造成上面提到的使用空值导致的错误。
Rust就不支持空值。但是通过枚举Option来标识一个值的无效或者缺失。定义如下:
enum Option<T> {
Some(T),
None,
}这里的<T>是泛型的内容。Option<T>包含在预导入模块中,可以直接使用,也可以在不适用Option::前缀的情况下直接使用Some和None。
一个Some值表示确定值是存在的,None就表示不存在值。之所以这个设计比空值好,这是因为无法像使用普通值一样使用Options的值,因为Option<T>和T是不同的类型,要想能够使用Option中的值,就需要显式处理。
这使得编码的过程不需要考虑一个值是否为空。通过使用match表达式来处理枚举的控制流结构来处理有值和无值的情况。
控制流运算符match
处理示例代码如下:
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);每个分支与枚举的变体相对应,如果变体有关联的数据,那么匹配的分支还可以绑定被匹配对象的部分值,正是通过这种方法从枚举变体中提取值。正是上面的Some(i) => ...分支,其中取出了Some变体中的值绑定到了i上。
match匹配必须穷举所有的可能
对于上面的例子,如果只匹配一条分支:
match x {
Some(i) => Some(i+1),
}那么编译是不会通过的。
同样,对于穷举可能很多,但是需要专门处理的可能很少的情况,可以使用通配符_来同一匹配不需要处理的可能。_放在所有分支的最后。
let some_u8_value = 08u;
match some_u8_value {
1 => println!("one"),
3 => println!("three"),
5 => println!("five"),
_ => (),
}再对于只关注一种可能的特别情况,可以使用if let来简化。==也就是说if let可以看作是match匹配只需要关注一种情况下的语法糖==。
let some_u8_value = Some(08u);
//match some_u8_value {
// Some(3) => println!("three"),
// _ => (),
//}
//简写为
if let Some(3) = some_u8_value {
println!("three")
}if let可以与else搭配使用,这里的else与match匹配中的_分支相同。
tags: 自定义数据类型