通过对《Rust 程序设计语言》,《通过例子学 Rust 中文版》以及令狐一冲老师对相关知识点的学习总结而成。
可以通过在代码中定义一个 IpAddrKind 枚举来表现这个概念并列出可能的 IP 地址类型,V4 和 V6。这被称为枚举的 成员(variants):
//枚举的定义
enum IpAddrKind {
V4,
V6,
}
//定义一个IP地址的结构体
struct IpAddr {
kind: IpAddrKind,
address: String,
}
//定义home变量去声明home IP地址的相关信息
let home = IpAddr {
kind: IpAddrKind::V4,
address: String::from("127.0.0.1"),
};
//定义loopback变量去声明环回口IP地址的相关信息
let loopback = IpAddr {
kind: IpAddrKind::V6,
address: String::from("::1"),
};
我们定义了一个有两个字段的结构体 IpAddr:IpAddrKind类型的 kind 字段和 String 类型 address 字段。我们有这个结构体的两个实例。
我们使用了一个结构体来将 kind 和 address 打包在一起,现在枚举成员就与值相关联了。
我们可以使用一种更简洁的方式来表达相同的概念,仅仅使用枚举并将数据直接放进每一个枚举成员而不是将枚举作为结构体的一部分。IpAddr 枚举的新定义表明了 V4 和 V6 成员都关联了 String 值:
enum IpAddr {
V4(String),
V6(String),
}
let home = IpAddr::V4(String::from("127.0.0.1"));
let loopback = IpAddr::V6(String::from("::1"));
用枚举替代结构体还有另一个优势:每个成员可以处理不同类型和数量的数据。IPv4 版本的 IP 地址总是含有四个值在 0 和 255 之间的数字部分。如果我们想要将 V4 地址存储为四个 u8 值而 V6 地址仍然表现为一个 String,这就不能使用结构体了。枚举则可以轻易地处理这个情况:
#![allow(unused)]
fn main() {
enum IpAddr {
V4(u8, u8, u8, u8),
V6(String),
}
let home = IpAddr::V4(127, 0, 0, 1);
let loopback = IpAddr::V6(String::from("::1"));
}
代码展示了使用枚举来存储两种不同 IP 地址的几种可能的选择。然而,事实证明存储和编码 IP 地址实在是太常见了以致标准库提供了一个开箱即用的定义!让我们看看标准库是如何定义 IpAddr 的:它正有着跟我们定义和使用的一样的枚举和成员,不过它将成员中的地址数据嵌入到了两个不同形式的结构体中,它们对不同的成员的定义是不同的:
struct Ipv4Addr {
// --snip--
}
struct Ipv6Addr {
// --snip--
}
enum IpAddr {
V4(Ipv4Addr),
V6(Ipv6Addr),
}
我们定义一个 Message 枚举,其每个成员都存储了不同数量和类型的值
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
这个枚举有四个含有不同类型的成员:
struct QuitMessage; // 类单元结构体
struct MoveMessage {
x: i32,
y: i32,
}
struct WriteMessage(String); // 元组结构体
struct ChangeColorMessage(i32, i32, i32); // 元组结构体
impl Message {
fn print(&self) {
match *self {
Message::Quit => println!("quit"),
Message::Move{x, y} => println!("Move x = {}, y = {}", x, y),
Message::ChangeColor(x, y, z) => println!("ChangeColor x = {}, y = {}, z = {}", x, y, z),
_ => println!("Write and others"),
}
}
}
let q = Message::Quit;
q.print();
let m = Message::Move(1, 2);
m.print();
let w = Message::Write(String::from("hello"));
w.print();
let c = Message::ChangeColor(1, 2, 3);
c.print();