枚举 定义枚举
定义一个 IP 地址(IPv4、IPv6)的枚举
1 2 3 4 enum IpAddrKind { V4, V6, }
创建枚举值
枚举名加上::再加上值就可以创建枚举值
1 2 let four = IpAddrKind::V4;let six = IpAddrKind::V6;
枚举作为函数参数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 enum IpAddrKind { V4, V6, } fn main () { let four = IpAddrKind::V4; let six = IpAddrKind::V6; route(four); route(six); route(IpAddrKind::V6); } fn route (ip_kind: IpAddrKind) {}
数据附加到枚举的变体中
不需要额外使用 struct
每个变体可以拥有不同的类型以及关联的数据量
1 2 3 4 5 6 7 8 9 enum IpAddrKind { V4(u8 , u8 , u8 , u8 ), V6(String ), } fn main () { let home = IpAddrKind::V4(127 , 0 , 0 , 1 ); let loopback = IpAddrKind::V6(String ::from("::1" )); }
1 2 3 4 5 6 7 8 9 10 11 12 13 enum Message { Quit, Move {x: i32 , y: i32 }, Write(String ), ChangeColor(i32 , i32 , i32 ), } fn main () { let q = Message::Quit; let m = Message::Move {x: 12 , y: 24 }; let w = Message::write(String ::from("hello" )); let c = Message::ChangeColor(0 , 255 , 255 ); }
为枚举定义方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 enum Message { Quit, Move {x: i32 , y: i32 }, Write(String ), ChangeColor(i32 , i32 , i32 ), } impl Message { fn call (&self ) {} } fn main () { let q = Message::Quit; let m = Message::Move {x: 12 , y: 24 }; let w = Message::write(String ::from("hello" )); let c = Message::ChangeColor(0 , 255 , 255 ); m.call(); }
Option 枚举
定义于标准库中
在 Prelude(预导入模块)中
描述了:某个值可能存在(某种类型)或不存在的情况
在 Rust 中没有 Null,在其他语言中,Null 是一个值,它表示“没有值”,一个变量可以处于两种状态:空值(null)、非空。Null 的问题在于:当你尝试像使用非 Null 值那种使用 Null 值的时候,就会引起某种错误;但是 Null 的概念还是有用的,描述了某种原因而变为无效或缺失的值。Rust 中提供了类似 Null 概念的枚举:Option<T>
1 2 3 4 enum option <T> { Some (T), None , }
因为 Option 枚举直接包含在 Prelude(预导入模块)中,所以可以直接使用
1 2 3 4 5 6 7 fn main () { let some_number = Some (5 ); let some_string = Some ("A String" ); let absent_number: Option <i32 > = None ; }
Option<T> VS Null
Option<T> 和 T 是不同的类型,不可以把 Option<T> 直接当成 T
若想使用 Option<T> 中的 T,必须将它转换为 T
1 2 3 4 5 6 7 fn main () { let x: i8 = 5 ; let y: Option <i8 > = Some (5 ); let sum = x + y; }
match
强大的控制流运算符 - match
允许一个值与一系列模式进行匹配,并执行匹配的模式对应的代码
模式可以是字面值、变量名、通配符…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 enum Coin { Penny, Nickel, Dime, Quarter, } fn value_in_cents (coin: Coin) -> u8 { match coin { Coin::Penny => 1 , Coin::Nickel => 5 , Coin::Dime => 10 , Coin::Quarter => 25 , } } fn main () {}
绑定值的模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #[derive(Debug)] enum UsState { Alabma, Alaska, } enum Coin { Penny, Nickel, Dime, Quarter, } fn value_in_cents (coin: Coin) -> u8 { match coin { Coin::Penny => { println! ("penny!" ); 1 }, Coin::Nickel => 5 , Coin::Dime => 10 , Coin::Quarter(state) => { println! ("state quarter from: {:?}!" , state); 25 }, } } fn main () { let c = Coin::Quarter(UsState::Alaska); println! ("{}" , value_in_cents(c)); }
匹配 Option<T> 1 2 3 4 5 6 7 8 9 10 11 12 fn main () { let five = Some (5 ); let six = plus_one(five); let none = plus_one(None ); } fn plus_one (x: Option <i32 >) -> Option <i32 > { match x { None => None , Some (i) => Some (i + 1 ), } }
match 匹配的时候必须穷举所有的可能,在上述的例子中,如果在 match 中少写了 None 条件,那么代码就会报错(non-exhaustive patterns: 'Nong' not covered),所以 match 必须穷举所有可能,才能确保代码的有效。
我们可以使用 _ 通配符,来代替其余没有列出的值
1 2 3 4 5 6 7 8 9 10 fn main () { let v = 0u8 ; match v { 1 => println! ("one" ), 3 => println! ("three" ), 5 => println! ("five" ), 7 => println! ("seven" ), _ => (), } }
if let
处理只关心一种匹配而忽略其它匹配的情况
更少的代码、更少的缩进、更少的模版代码
放弃了穷举的可能
可以把 if let 看作是 match 的语法糖
if let 也可以搭配 else 来进行使用
1 2 3 4 5 6 7 8 fn main () { let v = Some (0u8 ); if let Some (3 ) = v { println! ("three" ); } else { println! ("others" ); } }
以上代码等价于下列的代码
1 2 3 4 5 6 7 fn main () { let v = Some (0u8 ); match v { Some (3 ) => println! ("three" ), _ => println! ("others" ), } }