下面学习一下枚举的三种使用方式
1 )use 配合枚举
use 导入枚举变体
// 消除未使用代码的编译警告
#![allow(dead_code)]
enum Stage {
Beginner,
Advanced,
}
enum Role {
Student,
Teacher,
}
fn main() {
// 显式导入 Stage 下的两个变体(Beginner、Advanced),不用写 Stage::
use Stage::{Beginner, Advanced};
// 通配符 *:导入 Role 内部**所有变体**
use Role::*;
let stage = Beginner; // 等价 Stage::Beginner
let role = Student; // 等价 Role::Student
match stage {
Beginner => println!("初学者开启学习之旅!"),
Advanced => println!("进阶学习者正在深耕知识..."),
}
match role {
Student => println!("学生正在汲取知识!"),
Teacher => println!("老师在传播知识!"),
}
}Code language: Rust (rust)
输出结果
初学者开启学习之旅!
学生正在汲取知识!
use 枚举::{变体1,变体2}:选择性导入指定枚举成员;use 枚举::*:通配导入枚举全部变体;- 不使用
use时,必须完整书写Stage::Beginner。
2)C 风格枚举
#![allow(dead_code)]
// 隐式判别值:从 0 开始自动递增
enum Number {
Zero, // 0
One, // 1
Two, // 2
}
// 显式手动指定判别值
enum Color {
Red = 0xff0000,
Green = 0x00ff00,
Blue = 0x0000ff,
}
fn main() {
// C风格枚举可以直接强转整数
println!("zero is {}", Number::Zero as i32);
println!("one is {}", Number::One as i32);
println!("roses are #{:06x}", Color::Red as u32);
println!("violets are #{:06x}", Color::Blue as u32);
}Code language: PHP (php)

输出结果
zero is 0
one is 1
roses are #ff0000
violets are #0000ffCode language: CSS (css)
- 只有无数据的单元变体枚举才能强转整型;
- 自动赋值:第一个变体默认
0,后续依次+1; - Rust 枚举和 C 枚举本质不同:普通 Rust enum 可以携带数据,C风格只是特例。
如果枚举包含元组/结构体变体,无法 as 转换成整数。
经典案例
用 Enum + Box 实现单向链表
#![allow(dead_code)]
use crate::List::*;
enum List {
// Cons(元素, 指向下一节点的堆指针)
Cons(u32, Box<List>),
// Nil:链表终止标记(空节点)
Nil,
}
// 给枚举 List 绑定方法
impl List {
// 创建空链表
fn new() -> List {
Nil
}
// 在链表头部插入元素,返回新链表
fn prepend(self, elem: u32) -> List {
Cons(elem, Box::new(self))
}
// 获取链表长度
fn len(&self) -> u32 {
match *self {
// ref tail:借用尾部节点,不获取所有权
Cons(_, ref tail) => 1 + tail.len(),
Nil => 0
}
}
// 序列化为字符串输出
fn stringify(&self) -> String {
match *self {
Cons(head, ref tail) => {
format!("{}, {}", head, tail.stringify())
},
Nil => format!("Nil")
}
}
}
fn main() {
let mut list = List::new();
// 头部追加元素(后进先出)
list = list.prepend(1);
list = list.prepend(2);
list = list.prepend(3);
println!("链表长度: {}", list.len());
println!("{}", list.stringify());
}Code language: Rust (rust)
运行输出
链表长度: 3
3, 2, 1, Nil
说明
- 为什么要用
Box<List>
Cons(u32, List) // 非法!递归类型无限大小
Cons(u32, Box<List>) // Box 是堆上指针,固定大小Code language: PHP (php)
Rust 需要在编译期确定类型大小,直接递归List会无限嵌套;Box<T>把数据放到堆,栈只存指针,解决尺寸问题。
prepend(self):获取链表所有权
每次插入会消耗旧链表,构建新节点,属于不可变链表(函数式链表),不是传统可变链表。match *self+ref tailself类型是&List(借用),解引用*self匹配;
使用ref tail只借用内部数据,不抢夺所有权,保证.len()可以多次调用。- 缺陷提示
当前len()、stringify()是递归实现,链表很长时会触发栈溢出;生产环境一般改用循环迭代。
总结
- 枚举变体三类形式
enum Foo {
Unit, // 单元变体(C风格)
Tuple(i32, String), // 元组变体
Struct { x: f64 } // 结构体变体
}Code language: JavaScript (javascript)
use作用域:只在当前模块/代码块生效;- 链表案例是 Rust 官方经典入门示例,帮助理解:递归类型、
Box、所有权、借用、模式匹配;