6.1 Defining an Enum
1、Enum的使用场景,比如IP协议的版本,Any IP address can be either a version four or a version six address, but not both at the same time.
常规的enum的用法,和其他的语言差不多,很直观。
#[derive(Debug)]
enum IpAddrKind {
V4,
V6,
}
// 当作函数的参数传递,使用引用,避免所有权转移
fn route(ip_kind: &IpAddrKind) {
println!("ip version is {:?}", ip_kind); // 打印字符串:V4 or V6
}
fn main() {
let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
route(&four);
println!("{:?}", four);
route(&six);
println!("{:?}", six);
}
:::info enum 还可以额外携带数据,给枚举添加方法。 这2点和其他的编程语言有很大的不同。
:::
#[derive(Debug)]
enum Message { // 定义4种不同类型的enum的variants
Quit,
Move { x: i32, y: i32 }, // 用{}表示,类似结构体,带变量名
Write(String),
ChangeColor(i32, i32, i32), // 类似tuple,多个匿名的fields
}
// 给 enum 添加方法
impl Message {
fn call(&self) {
match self {
Message::Write(msg) => {
println!("Write : {}", msg);
}
Message::Move { x, y } => {
println!("Move, x={}, y={}", x, y);
}
Message::ChangeColor(a, b, c) => {
println!("ChangeColor {},{},{}", a, b, c);
}
_ => {}
}
}
}
fn main() {
let m = Message::Write(String::from("Hello"));
m.call();
let m = Message::Move { x: 10, y: 20 };
m.call();
let m = Message::ChangeColor(1, 2, 3);
m.call();
}
Option Enum 和 Null 的对比
Null 空指针的最大的问题就是:把null变量当作非none变量来使用,于是代码非常容易写错。
The problem with null values is that if you try to use a null value as a not-null value, you’ll get an error of some kind. Because this null or not-null property is pervasive, it’s extremely easy to make this kind of error.
但是这并不是Null的错误,因为,However, the concept that null is trying to express is still a useful one: a null is a value that is currently invalid or absent for some reason. Null是表示一个无效的值,这在程序中是有意义的。
As such, Rust does not have nulls, but it does have an enum that can encode the concept of a value being present or absent. Rust的做法和其他的语言类似,引入了**Option<T>**
的enum,**可以避免Null的问题。**
原因是,如果用户使用了Option
When we have a value of a type like i8 in Rust, the compiler will ensure that we always have a valid value.
We can proceed confidently without having to check for null before using that value.
Only when we have an Option
(or whatever type of value we’re working with) do we have to worry about possibly not having a value, and the compiler will make sure we handle that case before using the value.
enum Option<T> {
None,
Some(T),
}
In other words, you have to convert an Option
to a T before you can perform T operations with it. Generally, this helps catch one of the most common issues with null: assuming that something isn’t null when it actually is.
程序员在使用Option之前,必须先转换成T类型才能使用,从而避免了一个常见的问题:以为这个对象是不可能会Null的假设。
Option的使用方法: 1、如果一个对象有可能是为Null的,那么就必须要用Option包装起来 2、在使用的地方,一定要显式地去处理这个Option可能为Null的情况,6.2 The match Control Flow Construct
Rust 中的 match
语法,类似switch
语句,但是要匹配的模式更加丰富,可以支持literal values, variable names, wildcards
等等。
符号=>
前面的部分,被称作match arms
, 后面部分是表达式,可以是code block,要注意是的,match语句不需要显式地写break
来中断匹配,这点非常友好,避免了那么fallthrough
的写法会引入的问题。
enum Coin {
Penny,
Nickel,
Dime,
Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("Hello Penny");
1
},
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter => 25,
}
}
另外,match arm 的语法种,一个重要的特点是:bind to the parts of the values that match the pattern. 因为Rust 中的 enum 是可以额外附带数据的,在match中也可以提取出来。
#[derive(Debug)]
enum UsState {
Alabama,
Alaska,
}
enum Coin {
Penny,
Nickel,
Dime,
Quarter(UsState), // 附带数据的enum
}
fn value_in_cents(coin: Coin) -> u8 {
match coin {
Coin::Penny => {
println!("Hello Penny");
1
},
Coin::Nickel => 5,
Coin::Dime => 10,
Coin::Quarter(state) => { // 被 match arm 捕获
println!("State quarter from {:?}!", state);
25
},
}
}
fn main() {
value_in_cents(Coin::Quarter(UsState::Alaska));
}
6.3 Concise Control Flow with if let
在手机上继续去写的话,还是比较舒服的,但是不能在电脑上继续书写了。
只要是一种志在必得的手感,那么都可以继续关注我,没什么大的情况不了解的话,就这样子吧。
也许你可以自带风情的万种来解释,但是我不会理睬你的。