海宁市住房和城乡建设网站,哪家购物网站建设好,pc网站怎么建设流程,关于建设 医院网站的请示枚举#xff08;enumerations#xff09;#xff0c;也被称作 enums。match 允许我们将一个值与一系列的模式相比较#xff0c;并根据相匹配的模式执行相应代码。 1 枚举的定义
假设我们要跨省出行#xff0c;有多种交通工具供选择。常用的交通工具有飞机、火车、汽车和轮…枚举enumerations也被称作 enums。match 允许我们将一个值与一系列的模式相比较并根据相匹配的模式执行相应代码。 1 枚举的定义
假设我们要跨省出行有多种交通工具供选择。常用的交通工具有飞机、火车、汽车和轮船。这是我们常用的跨省出行乘坐交通工具的所有形式所以可以枚举出所有可能的值这也正是此枚举名字的由来。
可以通过在代码中定义一个 Vehicle 枚举来表现这个概念并列出可能的交通工具类型Airplane飞机、Train火车、Car汽车 和 Ship轮船 。这被称为枚举的成员variants
enum Vehicle {Airplane,Train,Car,Ship,
}如果现在我们要区分汽车到底是哪一种按照动力类型分类为汽油车、柴油车、混合动力车、电动车和燃料电池车。将动力类型和汽车做关联修改后的枚举如下
enum Vehicle {Airplane,Train,Car(PowerType),Ship,
}enum PowerType {Gasoline,Diesel,Mix,Electric,FuelCell,
}实际上枚举的成员中可内嵌多种多样的类型比如下面的例子一个 Message 枚举其每个成员都存储了不同数量和类型的值。
enum Message {Quit,Move { x: i32, y: i32 },Write(String),ChangeColor(i32, i32, i32),
}这个枚举有四个含有不同类型的成员
Quit 没有关联任何数据。Move 类似结构体包含命名字段。Write 包含单独一个 String。ChangeColor 包含三个 i32。
定义一个如上例中所示那样的有关联值的枚举的方式和定义多个不同类型的结构体的方式很相像除了枚举不使用 struct 关键字以及其所有成员都被组合在一起位于 Message 类型下。如下这些结构体可以包含与之前枚举成员中相同的数据
struct QuitMessage; // 类单元结构体
struct MoveMessage {x: i32,y: i32,
}
struct WriteMessage(String); // 元组结构体
struct ChangeColorMessage(i32, i32, i32); // 元组结构体不过如果我们使用不同的结构体由于它们都有不同的类型我们将不能像使用上例中定义的 Message 枚举那样轻易的定义一个能够处理这些不同类型的结构体的函数因为枚举是单独一个类型。
结构体和枚举还有另一个相似点就像可以使用 impl 来为结构体定义方法那样也可以在枚举上定义方法。这是一个定义于我们 Message 枚举上的叫做 call 的方法 impl Message {fn call(self) {// 在这里定义方法体}}let m Message::Write(String::from(hello));m.call();方法体使用了 self 来获取调用方法的值。这个例子中创建了一个值为 Message::Write(String::from(hello)) 的变量 m而且这就是当 m.call() 运行时 call 方法中的 self 的值。
2 match 控制流结构
match 允许我们将一个值与一系列的模式相比较并根据相匹配的模式执行相应代码。模式可由字面值、变量、通配符和许多其他内容构成。
可以把 match 表达式想象成某种硬币分类器硬币滑入有着不同大小孔洞的轨道每一个硬币都会掉入符合它大小的孔洞。同样地值也会通过 match 的每一个模式并且在遇到第一个 “符合” 的模式时值会进入相关联的代码块并在执行中被使用。
比如我们想得到从一个城市到另一个城市的票价不同的交通工具价格是不一样的。假设这两座城市无法通过轮渡的方式运输所以下面的示例中返回了 -1表征无效。
enum Vehicle {Airplane,Train,Car,Ship,
}fn fare(vehicle: Vehicle) - i32 {match vehicle {Vehicle::Airplane 800,Vehicle::Train 100,Vehicle::Car 200,Vehicle::Ship -1}
}这看起来非常像 if 所使用的条件表达式不过这里有一个非常大的区别对于 if表达式必须返回一个布尔值而这里它可以是任何类型的。
当 match 表达式执行时它将结果值按顺序与每一个分支的模式相比较。如果模式匹配了这个值这个模式相关联的代码将被执行。如果模式并不匹配这个值将继续执行下一个分支非常类似一个硬币分类器。可以拥有任意多的分支。每个分支相关联的代码是一个表达式而表达式的结果值将作为整个 match 表达式的返回值。如果分支代码较短的话通常不使用大括号。如果想要在分支中运行多行代码可以使用大括号而分支后的逗号是可选的。
enum Vehicle {Airplane,Train,Car,Ship,
}fn fare(vehicle: Vehicle) - i32 {match vehicle {Vehicle::Airplane 800,Vehicle::Train 100,Vehicle::Car 200,Vehicle::Ship {println!(Not supported by ships!);-1}}
}绑定值的模式
匹配分支的另一个有用的功能是可以绑定匹配的模式的部分值。这也就是如何从枚举成员中提取值的。
下面的例子运行后会打印出汽车的动力类型时混动Mix。
#[derive(Debug)]
enum PowerType {Gasoline,Diesel,Mix,Electric,FuelCell,
}enum Vehicle {Airplane,Train,Car(PowerType),Ship,
}fn fare(vehicle: Vehicle) - i32 {match vehicle {Vehicle::Airplane 800,Vehicle::Train 100,Vehicle::Car(powerType) {println!(The power type of the car is {:?}!, powerType);200},Vehicle::Ship {println!(Not supported by ships!);-1}}
}fn main() {fare(Vehicle::Ship);fare(Vehicle::Car(PowerType::Mix));
}运行结果
Not supported by ships!
The power type of the car is Mix!匹配 Option
Rust 并没有空值不过它确实拥有一个可以编码存在或不存在概念的枚举。这个枚举是 OptionT而且它定义于标准库中如下
enum OptionT {None,Some(T),
}OptionT 枚举是如此有用以至于它甚至被包含在了 prelude 之中你不需要将其显式引入作用域。另外它的成员也是如此可以不需要 Option:: 前缀来直接使用 Some 和 None。即便如此 OptionT 也仍是常规的枚举Some(T) 和 None 仍是 OptionT 的成员。
T 语法是一个我们还未讲到的 Rust 功能。它是一个泛型类型参数。
比如我们想要编写一个函数它获取一个 Optioni32 如果其中含有一个值将其加一。如果其中没有值函数应该返回 None 值而不尝试执行任何操作。
fn plus_one(x: Optioni32) - Optioni32 {match x {None None,Some(i) Some(i 1),}
}fn main() {let five Some(5);let six plus_one(five);let none plus_one(None);println!(six is {:?}, none is {:?}, six, none);
} 运行结果
six is Some(6), none is None如果去除上例中匹配分支内 None None 这句代码实际上会报错。
Rust 中的匹配是穷尽的exhaustive必须穷举到最后的可能性来使代码有效。
fn plus_one(x: Optioni32) - Optioni32 {match x {Some(i) Some(i 1),}
}fn main() {let five Some(5);let six plus_one(five);let none plus_one(None);println!(six is {:?}, none is {:?}, six, none);
} 运行结果
Exited with status 101Standard ErrorCompiling playground v0.0.1 (/playground)
error[E0004]: non-exhaustive patterns: None not covered-- src/main.rs:2:11|
2 | match x {| ^ pattern None not covered|
note: Optioni32 defined here-- /playground/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:570:1|
570 | pub enum OptionT {| ^^^^^^^^^^^^^^^^^^
...
574 | None,| ---- not covered note: the matched value is of type Optioni32
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown|
3 ~ Some(i) Some(i 1),
4 ~ None todo!(),|For more information about this error, try rustc --explain E0004.
error: could not compile playground (bin playground) due to 1 previous error
通配模式和 _ 占位符
我们希望对一些特定的值采取特殊操作而对其他的值采取默认操作。比如下面的例子只有飞机和火车给出票价不支持其他交通方式。
#[derive(Debug)]
enum Vehicle {Airplane,Train,Car,Ship,
}fn fare(vehicle: Vehicle) - i32 {match vehicle {Vehicle::Airplane 800,Vehicle::Train 100,other {println!(Not support {:?}, other);-1}}
}fn main() {let price fare(Vehicle::Airplane);println!(The price of air tickets is {}, price);fare(Vehicle::Car);
}运行结果
The price of air tickets is 800
Not support Car对于前两个分支匹配模式是字面值 Vehicle::Airplane 和 Vehicle::Train最后一个分支则涵盖了所有其他可能的值模式是我们命名为 other 的一个变量。
即使我们没有列出 Vehicle 所有可能的值这段代码依然能够编译因为最后一个模式将匹配所有未被特殊列出的值。这种通配模式满足了 match 必须被穷尽的要求。请注意我们必须将通配分支放在最后因为模式是按顺序匹配的。如果我们在通配分支后添加其他分支Rust 将会警告我们因为此后的分支永远不会被匹配到。
Rust 还提供了一个模式当我们不想使用通配模式获取的值时请使用 _ 这是一个特殊的模式可以匹配任意值而不绑定到该值。这告诉 Rust 我们不会使用这个值所以 Rust 也不会警告我们存在未使用的变量。
#[derive(Debug)]
enum Vehicle {Airplane,Train,Car,Ship,
}fn fare(vehicle: Vehicle) - i32 {match vehicle {Vehicle::Airplane 800,Vehicle::Train 100,_ {println!(Not support);-1}}
}fn main() {let price fare(Vehicle::Airplane);println!(The price of air tickets is {}, price);fare(Vehicle::Car);
}运行结果
The price of air tickets is 800
Not support这个例子也满足穷举性要求因为我们在最后一个分支中明确地忽略了其他的值。我们没有忘记处理任何东西。
3 if let 简洁控制流
if let 语法让我们以一种不那么冗长的方式结合 if 和 let来处理只匹配一个模式的值而忽略其他模式的情况。
enum Vehicle {Airplane,Train,Car,Ship,
}fn fare(vehicle: Vehicle) - i32 {if let Vehicle::Airplane vehicle {println!(Travel by plane);return 800;}return -1;
}fn main() {let mut price fare(Vehicle::Airplane);println!(The price of air tickets is {}, price);price fare(Vehicle::Car);println!(The price of car tickets is {}, price);
}运行结果
Travel by plane
The price of air tickets is 800
The price of car tickets is -1if let 语法获取通过等号分隔的一个模式和一个表达式。它的工作方式与 match 相同这里的表达式对应 match 而模式则对应第一个分支。在这个例子中模式是 Vehicle::Airplane。就跟在对应的 match 分支中一样。模式不匹配时 if let 块中的代码不会执行。
使用 if let 意味着编写更少代码更少的缩进和更少的样板代码。然而这样会失去 match 强制要求的穷尽性检查。match 和 if let 之间的选择依赖特定的环境以及增加简洁度和失去穷尽性检查的权衡取舍。
换句话说可以认为 if let 是 match 的一个语法糖它当值匹配某一模式时执行代码而忽略所有其他值。
还可以在 if let 中包含一个 else。
enum Vehicle {Airplane,Train,Car,Ship,
}fn fare(vehicle: Vehicle) - i32 {if let Vehicle::Airplane vehicle {println!(Travel by plane);return 800;} else {return -1;}
}fn main() {let mut price fare(Vehicle::Airplane);println!(The price of air tickets is {}, price);price fare(Vehicle::Train);println!(The price of train tickets is {}, price);
}运行结果
Travel by plane
The price of air tickets is 800
The price of train tickets is -1参考链接
Rust 官方网站https://www.rust-lang.org/zh-CNRust 官方文档https://doc.rust-lang.org/Rust Playhttps://play.rust-lang.org/《Rust 程序设计语言》