枚举 结构体将字段与数据聚合,而枚举可以将同一类型的东西(同时你可以将它可能的情况列举出来)作为一个集合,使用IP地址举例如下
1 2 3 4 enum IpAddrKind { v4, v6, }
枚举值 可使用::
访问枚举值
1 2 let ipv4 = IpAddrKind::v4;let ipv6 = IpAddrKind::v6;
也可将其传入函数,如func(IpAddrKind::v4)
也可结合结构体使用如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 enum IpAddrKind { V4, V6, } struct IpAddr { kind: IpAddrKind, address: String , } let home = IpAddr { kind: IpAddrKind::V4, address: String ::from ("127.0.0.1" ), }; let loopback = IpAddr { kind: IpAddrKind::V6, address: String ::from ("::1" ), };
也可直接指定枚举值类型如
1 2 3 4 5 6 7 enum IpAddr { V4 (String ), V6 (String ), } let home = IpAddr::V4 (String ::from ("127.0.0.1" ));let loopback = IpAddr::V6 (String ::from ("::1" ));
此时,IpAddr::V4()
实际上为一个获取String
参数并返回IpAddr
类型示例的函数调用,而这些构造函数会被自动定义,枚举可以为每个值指定不同的数据类型,例如
1 2 3 4 5 6 7 enum IpAddr { V4 (u8 , u8 , u8 , u8 ), V6 (String ), } let home = IpAddr::V4 (127 , 0 , 0 , 1 );let loopback = IpAddr::V6 (String ::from ("::1" ));
可以将任意类型的数据放入枚举成员中,例如字符串,数字或者结构体,甚至可以嵌套枚举
以下为一个多种成员类型的枚举类型
1 2 3 4 5 6 enum Message { Quit, Move { x: i32 , y: i32 }, Write (String ), ChangeColor (i32 , i32 , i32 ), }
该枚举类型有四个成员,分别为:
Quit
没有关联任何数据。
Move
类似结构体包含命名字段。
Write
包含单独一个 String
。
ChangeColor
包含三个 i32
。
如果使用结构体的话,他将会是这样,如果不能使用枚举类型的话,使用结构体需要定义四个不同的结构体类型
1 2 3 4 5 6 7 struct QuitMessage ; struct MoveMessage { x: i32 , y: i32 , } struct WriteMessage (String ); struct ChangeColorMessage (i32 , i32 , i32 );
枚举同结构体一样可以使用impl
来定义方法
1 2 3 4 5 6 7 8 impl Message { fn call (&self ) { } } let m = Message::Write (String ::from ("hello" ));m.call ();
Option
枚举Option
是标准库定义的另一个枚举,这个枚举可以表示一个空值,Rust没有nil
,nullptr
,NULL
那样的空值,取而代之为如下
1 2 3 4 enum Option <T> { None , Some (T), }
可以不使用Option::
前缀来直接使用Some
与None
,但即便如此Option<T>
也是常规的枚举, Some<T>
与None
是其成员,以下是一些例子
1 2 3 4 let some_num = Some (6 );let some_char = Some ('a' );let absent_num : Option <i32 > = None ;
在上述例子中,some_num
的类型是Option<i32>
,some_char
的类型是Option<char>
,对于absent_num
则通过: Option<i32>
显示的指明其类型
当有一个Some
值时,我们就知道存在一个值,而这个值保存在 Some
中。当有个 None
值时,在某种意义上,它跟空值具有相同的意义:并没有一个有效的值。这样做会比空值更好,因为Option<T>
和 T
(这里 T
可以是任何类型)是不同的类型,编译器不允许像一个肯定有效的值那样使用 Option<T>
1 2 3 4 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 18 19 20 enum ClothingSize { Size_XS, Szie_S, Size_M, Size_L, Size_XL, } fn get_sleeve_len (clothing_size: ClothingSize) -> u8 { match clothing_size { ClothingSize::Size_XS => { println! ("This is XS" ); 10 } ClothingSize::Szie_S => 20 , ClothingSize::Size_M => 30 , ClothingSize::Size_L => 40 , ClothingSize::Size_XL => 50 , } }
绑定值的模式 匹配分支的另一个功能是可以绑定匹配模式的部分值,这也就是如何从枚举成员中提取值的。
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 enum Brand { AAA, BBB } enum ClothingSize { Size_XS, Szie_S, Size_M, Size_L (Brand), Size_XL, } fn get_sleeve_len (clothing_size: ClothingSize) -> u8 { match clothing_size { ClothingSize::Size_XS => { println! ("This is XS" ); 10 } ClothingSize::Szie_S => 20 , ClothingSize::Size_M => 30 , ClothingSize::Size_L (brand) => { println! ("clothing brand is {:?}" , brand); 40 }, ClothingSize::Size_XL => 50 , } }
在以上场景中,调用get_sleeve_len(ClothingSize::Size_L(Brand::AAA))
,传入函数内部的clothing_size
遇到ClothingSize::Size_L(brand)
会匹配上,接着就可以直接使用AAA
这个值
匹配Option<T>
Option<T>
也可以被用作match
匹配,例如一个函数,接受一个类型为Option<T>
的参数,如果其中有值,则将其加一,如果没有则不进行操作
1 2 3 4 5 6 7 8 9 10 fn plus_one (x: Option <i32 >) -> Option <i32 > { match x { None => None , Some (i) => Some (i + 1 ), } } let five = Some (5 );let six = plus_one (five);let none = plus_one (None );
匹配的穷尽性,通配模式与占位符_
匹配需要列出所有的可能,所有可能出现的值都必须能匹配到,在Rust
中可以使用通配模式与_
占位符来实现穷尽例如
1 2 3 4 5 6 7 8 9 10 let num = rand ();match num { 7 => deal_seven (), 9 => deal_nine (), other => deal_other (other), } fn deal_seven () {}fn deal_nine () {}fn deal_other (num: u8 ) {}
对于前两个分支,匹配模式是字面值 7
和 9
,最后一个分支则涵盖了所有其他可能的值,模式是我们命名为 other
的一个变量。other
分支的代码通过将其传递给 deal_other
函数来使用这个变量。
通配模式应该放在最后一位,因为match
是按照分支顺序依次匹配的
如果不想使用通配模式获取的值,使用_
来替代,其可以匹配任意值而不绑定到该值
1 2 3 4 5 6 7 8 9 10 11 12 let num = rand ();match num { 7 => deal_seven (), 9 => deal_nine (), _ => deal_other (), _ => (), } fn deal_seven () {}fn deal_nine () {}fn deal_other () {}
if let
简洁控制流如果有以下类似的逻辑
1 2 3 4 5 let config_max = Some (3u8 );match config_max { Some (max) => println! ("The maximum is configured to be {}" , max), _ => (), }
仅关心Some
得值,其余不做任何操作,可使用if let
来简写
1 2 3 4 let config_max = Some (3u8 );if let Some (max) = config_max { println! ("The maximum is configured to be {}" , max); }