喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)
6.1.1. 什么是枚举
枚举允许我们列举所有可能的值来定义一个类型。这与其他编程语言中的枚举类似,但 Rust 的枚举更加灵活和强大,因为它们可以关联数据和方法,类似于其他语言中的类或结构体。
6.1.2. 定义枚举
举个例子,比如说IP地址无非就只有2种——IPv4和IPv6,要么是IPv4要么是IPv6,这种情况就非常适合使用枚举类型,因为枚举的值也只能是它所有变体(枚举所有可能的值)里的一个。
enum IpAddrKind{
V4,
V6,
}
这个代码使用enum
关键字声明了一个叫IpAddrkind
的枚举类型,它有两个类型——一个是V4
,一个是V6
,分别代表IPv4和IPv6。
6.1.3. 枚举值
表示(创建)枚举值非常简单,格式为枚举类型的名字::变体
,例如:
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
枚举的变体都在其标识符所在的空间下,它的标识符就是这个枚举类型的名。
我们可以声明一个函数,它接收IpAddrKind
这个类型作为它的参数,而传递的值就即可以是V4
也可以是V6
:
fn route(ip_addr: IpAddrKind) {
match ip_addr {
IpAddrKind::V4 => println!("IPv4"),
IpAddrKind::V6 => println!("IPv6"),
}
}
让我们试试效果:
整体代码:
enum IpAddrKind{
V4,
V6,
}
fn main() {
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
// 调用函数
route(four);
route(six);
route(IpAddrKind::V4);
}
fn route(ip_addr: IpAddrKind) {
match ip_addr {
IpAddrKind::V4 => println!("IPv4"),
IpAddrKind::V6 => println!("IPv6"),
}
}
输出:
IPv4
IPv6
IPv4
6.1.3. 将数据附加到枚举的变体中
枚举类型是一种自定义的数据类型,所以它可以作为结构体里面字段的类型,例如:
struct IpAddr {
kind: IpAddrKind,
address: String,
}
IpAddr
下的Kind
的类型是IpAddrKind
,存储网络协议;它的另一个字段address
是字符串类型,存储具体的IP地址。
通过这样的结构体,我们可以在main()
函数中声明一些存储IPv4、IPv6信息的变量:
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"),
};
}
Rust允许数据直接附加到枚举的变体中,例如:
enum IpAddr {
V4(String),
V6(String),
}
在每个变体的后边加上一个类型(不一定都是同一个类型)。例如这里V4
和V6
这两个变体后都跟了String
类型。
这种做法的优点是:
- 不需要额外使用struct
- 每个变体可以拥有不同的类型以及相关联的数据量
比如说:
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}
IPv4实际上是由4个32位的数字(也就是u8
的容量)组成的,而IPv6是字符串,所以就应该使用String
。如果我们想要将V4
地址存储为四个u8
值,但仍将V6
地址表示为一个String
值,我们将无法使用结构体。枚举可以轻松处理这种情况。
我们来重写一下6.1.3中的代码:
enum IpAddrKind{
V4(u8, u8, u8, u8),
V6(String),
}
fn main() {
let home = IpAddrKind::V4(127, 0, 0, 1);
let loopback = IpAddrKind::V6(String::from("::1"));
}
确实比前文的代码少多了。
6.1.4. 标准库中的IpAddr
事实上,标准库中就提供了关于IP地址的枚举类型,看一下官方是怎么写的
struct Ipv4Addr {
// --snip--
}
struct Ipv6Addr {
// --snip--
}
enum IpAddr {
V4(Ipv4Addr),
V6(Ipv6Addr),
}
Ipv4Addr
和Ipv6Addr
的内容这里没有写出来,但这不是重点。重点是此代码说明任何类型的数据放入枚举变体中都是可以的:例如字符串、数字类型或结构。甚至可以包含另一个枚举。
6.1.5. 在枚举类型使用方法(Method)
方法(Method)的概念在上一个文章中就有涉及,这里不过多阐述。定义方法使用impl
关键字,如下例:
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
impl Message {
fn call(&self) {
println!("Something happens");
}
}
fn main(){
let m = Message::Write(String::from("hello"));
m.call();
}
该枚举有四种不同类型的变体:
Quit
:没有关联任何数据。Move
:包含了一个匿名的结构体。Write
:包含一个String
。ChangeColor
:包括三个i32
值。
在主函数里声明了变量m
为Message
这个枚举类型下的Write
变体,并且附带了String
类型的hello
。然后又在m
上使用了方法call
,就会打印Something happens
。