Rust 枚举与模式
枚举
例子 1
pub enum Car {
Benz,
Ferrari,
}
fn get_car(car: Car) -> Engine<String> {
match car {
Car::Benz => Engine::new("V8".to_string(), 8),
Car::Ferrari => Engine::FERRARI,
}
}
例子 2
给枚举设置参数
enum HttpStatus {
Ok = 200,
NotModified = 304,
NotFound = 404
}
例子 3
可以直接使用 as
强制转换为整数
assert_eq!(HttpStatus::Ok as i32, 200);
例子 4
结构体一样,编译器能为你实现 == 运算符等特性,但你必须明确提出要求
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum TimeUnit {
Seconds, Minutes, Hours, Days, Months, Years,
}
带数据的枚举
/// 刻意四舍五入后的时间戳,所以程序会显示“6个月前”
/// 而非“2016年2月9日上午9点49分”
#[derive(Copy, Clone, Debug, PartialEq)]
enum RoughTime {
InThePast(TimeUnit, u32),
JustNow,
InTheFuture(TimeUnit, u32),
}
let four_score_and_seven_years_ago =
RoughTime::InThePast(TimeUnit::Years, 4 * 20 + 7);
let three_hours_from_now =
RoughTime::InTheFuture(TimeUnit::Hours, 3);
//包含字段名称的结构体
enum Shape {
Sphere { center: Point3d, radius: f32 },
Cuboid { corner1: Point3d, corner2: Point3d },
}
let unit_sphere = Shape::Sphere {
center: ORIGIN,
radius: 1.0,
};
内存中的枚举会占用 8 个字符
用枚举表示富数据结构
use std::collections::HashMap;
enum Json {
Null,
Boolean(bool),
Number(f64),
String(String),
Array(Vec<Json>),
Object(Box<HashMap<String, Json>>),
}
泛型枚举
枚举可以是泛型的。Rust 标准库中的两个例子是该语言中最常用的数据类型:
enum Option<T> {
None,
Some(T),
}
enum Result<T, E> {
Ok(T),
Err(E),
}
模式
Rust 不允许你通过编写 rough_time.0 和 rough_time.1 来直接访问它们,因为毕竟 rough_time 也可能是没有字段的,比如 RoughTime::JustNow。
你需要一个 match 表达式:
1 fn rough_time_to_english(rt: RoughTime) -> String {
2 match rt {
3 RoughTime::InThePast(units, count) =>
4 format!("{} {} ago", count, units.plural()),
5 RoughTime::JustNow =>
6 format!("just now"),
7 RoughTime::InTheFuture(units, count) =>
8 format!("{} {} from now", count, units.plural()),
9 }
10 }
模式中的字面量、变量和通配符
其他字面量也可以用作模式.
let calendar = match settings.get_string("calendar") {
"gregorian" => Calendar::Gregorian,
"chinese" => Calendar::Chinese,
"ethiopian" => Calendar::Ethiopian,
other => return parse_error("calendar", other),
};
通配符模式
let caption = match photo.tagged_pet() {
Pet::Tyrannosaur => "RRRAAAAAHHHHHH",
Pet::Samoyed => "*dog thoughts*",
_ => "I'm cute, love me", // 一般性捕获,对任意Pet都生效
};
元组型模式与结构体型模式
元组型模式匹配元组。每当你想要在单次 match 中获取多条数据时,元组型模式都非常有用.
fn describe_point(x: i32, y: i32) -> &'static str {
use std::cmp::Ordering::*;
match (x.cmp(&0), y.cmp(&0)) {
(Equal, Equal) => "at the origin",
(_, Equal) => "on the x axis",
(Equal, _) => "on the y axis",
(Greater, Greater) => "in the first quadrant",
(Less, Greater) => "in the second quadrant",
_ => "somewhere else",
}
}
结构体型模式使用花括号,就像结构体表达式一样。结构体型模式包含每个字段的子模式.
match balloon.location {
Point { x: 0, y: height } =>
println!("straight up {} meters", height),
Point { x: x, y: y } =>
println!("at ({}m, {}m)", x, y),
}
数组型模式与切片型模式
fn hsl_to_rgb(hsl: [u8; 3]) -> [u8; 3] {
match hsl {
[_, _, 0] => [0, 0, 0],
[_, _, 255] => [255, 255, 255],
...
}
}
引用型模式
match account {
Account { name, language, .. } => {
ui.greet(&name, &language);
ui.show_settings(&account); // 错误:借用已移动的值`account`
}
}
匹配守卫
fn check_move(current_hex: Hex, click: Point) -> game::Result<Hex> {
match point_to_hex(click) {
None =>
Err("That's not a game space."),
Some(current_hex) => // 如果用户单击current_hex,就会尝试匹配
//(其实它不起作用:请参见下面的解释)
Err("You are already there! You must click somewhere else."),
Some(other_hex) =>
Ok(other_hex)
}
}
匹配多种可能性
let at_end = match chars.peek() {
Some(&'\r' | &'\n') | None => true,
_ => false,
};
使用 @模式绑定
match self.get_selection() {
Shape::Rect(top_left, bottom_right) => {
optimized_paint(&Shape::Rect(top_left, bottom_right))
}
other_shape => {
paint_outline(other_shape.get_outline())
}
}
模式能用在哪里
尽管模式在 match 表达式中作用最为突出,但它们也可以出现在其他一些地方,通常用于代替标识符。但无论出现在哪里,其含义都是一样的:Rust 不是要将值存储到单个变量中,而是使用模式匹配来拆分值。
// 把结构体解包成3个局部变量……
let Track { album, track_number, title, .. } = song;
// ……解包某个作为函数参数传入的元组
fn distance_to((x, y): (f64, f64)) -> f64 { ... }
// ……迭代某个HashMap上的键和值
for (id, document) in &cache_map {
println!("Document #{}: {}", id, document.title);
}
// ……自动对闭包参数解引用(当其他代码给你传入引用,
// 而你更想要一个副本时会很有用)
let sum = numbers.fold(0, |a, &num| a + num);
附件
模式对照表
模式类型 | 例子 | 注意事项 |
---|---|---|
字面量 | "name" |
匹配一个确切的值;也允许匹配常量名称 |
范围 | 0 ..= 100 |
匹配范围内的任何值,包括可能给定的结束值 |
通配符 | _ |
匹配任何值并忽略它 |
变量 | name |
类似于 _,但会把值移动或复制到新的局部变量中 |
引用变量 | ref field |
借用对匹配值的引用,而不是移动或复制它 |
与子模式绑定 | val @ 0 ..= 99 |
使用 @ 左边的变量名,匹配其右边的模式 |
枚举型模式 | Some(value) |
|
元组型模式 | (key, value) |
|
数组型模式 | [a, b, c, d, e, f, g] |
|
切片型模式 | [first, second] |
|
结构体型模式 | Color(r, g, b) |
|
引用 | &value |
|
或多个模式 | `'a' | 'A'` |
守卫表达式 | x if x * x <= r2 |
评论