enum NUM
{
one,
two,
}
我们创建了一个枚举类型,此枚举包含两个枚举变量,one和two
我们可以给变量赋予枚举值:
fn main()
{
let a=NUM::one;
let b=NUM::two;
}
我么能否使用println!来尝试出枚举的值?
很遗憾,不能,不过,我们可以使用上一节我们学到的:
#[derive(Debug)]
enum NUM{
one,
two,
}
fn main()
{
let a=NUM::one;
let b=NUM::two;
println!("{:?}{:}",a,b);
}
注意加上#[derive(Debug)]
这个说明:这样我们就可以打印出枚举的值了。
struct _type{
num:NUM,
a:u32,
b:String,
}
我们在一个结构体的字段中创建了一个num字段,其是我们刚才创建的enum NUM类型。
现在,我们可以创建结构体的实例变量:
fn main()
{
let sb1=_type{
num:NUM::one,
a:88,
b:String::from("ylh"),
};
let sb2=_type{
num:NUM::two,
a:100,
b:String::from("abcd"),
};
}
我们来访问这个结构体实例变量:
println!("{:#?}{:#?}",sb1,sb2);
别忘了在结构体前面加上 #[derive(Debug)]
标识符。
枚举的独特之处:
enum Ex1{
Name(String),
Age(u32),
}
我们创建了一个枚举,这个枚举的字段绑定了两个值
,分别是String的Name和u32的Age,
我们直接将数据附加到枚举的每个成员上,这样就不需要一个额外的结构体了。
我们像上面使用结构体那样,使用这个枚举,创建一个实例变量:
fn main()
{
let n1=Ex1::Name(String::from("ylh"));
let n2=Ex1::Age(18);
println!("{:#?}{:#?}",n1,n2);
}
别忘了加上控制打印的说明,运行如下:
此外,我们还可以在枚举中定义含有多个属性的字段:
enum Ex1{
Name(String,String),
Age(u32,u32,u32),
}
这是结构体没有的,而枚举特有的一个特性。
甚至我们还可以有内嵌了多种多样的类型的枚举:
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
这个枚举有四个含有不同类型的成员:
这使得我们的枚举更加具有灵活性
。
但是,如果我们要用结构体来描述这个枚举,他很可能是这样的:
struct A;
struct B{
x:i32
y:i32
}
struct C(String);
struct D(i32,i32,i32);
我们创建了四个结构体
来描述这一个枚举
,可以清晰地看到结构体处理不同的类型数据太麻烦了。
因为枚举是单独一个类型,使用这个类型可以轻易的处理多种不同的类型。
枚举也可以像结构体那样定义方法
:
impl Message{
fn show(&self){
//定义一些方法
}
}
fn main()
{
let a=Message::Write(String::from("ylh));
a.show(); //调用此方法
}
Rust没有像C那样的NULL类型,NULL(空值)指的是:空值尝试表达的概念仍然是有意义的:空值是一个因为某种原因目前无效或缺失的值。
Rust提供了一个枚举Option让我们来处理空值
的情况:
//Option在标准库中的定义:
enum Option<T>{
None,
Some(T),
}
这是一个拥有存在和不存在
的枚举:Option
Option::
限定符。Option 枚举是如此有用以至于它甚至被包含在了 prelude 之中,你不需要将其显式引入作用域。另外,它的成员也是如此,可以不需要 Option:: 前缀来直接使用 Some 和 None。即便如此 Option 也仍是常规的枚举,Some(T) 和 None 仍是 Option 的成员。
我们可以指定任意类型,T会自动推断。
但我们指定是一个None时,Rust 需要我们指定 Option 整体的类型,因为编译器只通过 None 值无法推断出 Some 成员保存的值的类型。
注意:我们无须自己写一个Option,此枚举是标准库自带的,可以直接使用
最后一行我们告诉 Rust 希望 absent_number 是 Option 类型的:
fn main(){
let some_number = Some(5);
let some_char = Some('e');
let absent_number:Option<i32> = None;
}
Rust不知道如何将确定的类型与Option类型的值相加:
let a:i32=8;
let b=Some(16);
let sum=a+b; //出错
当在 Rust 中拥有一个像 i8 这样类型的值时,编译器确保它总是有一个有效的值。我们可以自信使用而无需做空值检查。只有当使用 Option(或者任何用到的类型)的时候需要担心可能没有值,而编译器会确保我们在使用值之前处理了为空的情况。
换句话说,在对 Option 进行 T 的运算之前必须将其转换为 T。
简而言之:如果你有一个值想要是空,你就把他放在Option
所以我们不能将确定的类型与Option 类型在一起做任何操作,Rust也提供了一些方法.
你可以把Option类型转换为T类型,这样他就一定不会是一个空值了,可以与确定的类型在一起操作了。
那么如何转换呢,我还没有学到,以后再说。
match 表达式是这么一个处理枚举的控制流结构:它会根据枚举的成员运行不同的代码,这些代码可以使用匹配到的值中的数据。
enum Ex2{
a,
b,
c,
d
}
fn cmp(this:Ex2)->u32{
match this {
Ex2::a=>1,
Ex2::b=>5,
Ex2::c=>10,
Ex2::d=>100,
}
}
fn main()
{
let num=Ex2::c;
println!("{}",cmp(num));
}
我们有一个函数,接受一个枚举,用match来匹配枚举,当具有不同的枚举值时,他们的值也不同。
match语句返回一个表达式,我们使用{}大括号将几条语句或小表达式集合在一起成为一个大的表达式:
fn cmp(this:Ex2)->u32{
match this {
Ex2::a=>{
println!("a");
1
},
Ex2::b=>{
println!("b");
5
}
Ex2::c=>{
println!("c");
10
}
Ex2::d=>{
println!("d");
100
},
}
}
在一个枚举中包含另一个枚举值
#[derive(Debug)]
enum No{
One,
Two,
Three,
}
enum Ex2{
a,
b,
c,
d(No)
}
fn cmp(this:Ex2)->u32{
match this {
Ex2::a=>1,
Ex2::b=>5,
Ex2::c=>10,
Ex2::d(value)=>{
println!("{:?}",value);
100
},
}
}
fn main()
{
let num=Ex2::d(No::Three);
println!("{}",cmp(num));
}
运行得:
我们在num变量中的d里面绑定了 No::Three
,当进入到match时,会匹配,发现d是符合条件的,进入println!宏,打印此value,即No::Three。
fn main(){
let num1=Some(55);
let name_none:Option<i32>=None;
test_match(num1);
test_match(name_none);
println!("{:?}",num1);
println!("{:?}",name_none);
}
fn test_match(this:Option<i32>)->Option<i32>{
match this {
Some(i)=>{
println!("Find it !!!");
Some(i+10)
}
None=>None,
}
}
枚举必须是穷尽的,他必须包含所有可能出现的情况。
fn main() {
fn plus_one(x: i32) -> i32 {
match x {
5=>{
println!("yes!");
return 10;
}
_=>{
println!("None!");
return 100;
}
}
}
let five = 5;
let none = plus_one(50);
}
_
表示任意情况,把它放在最后面,可以保证枚举的结束。
_
打印None 返回100.使用match控制流:
我们创建一个的Option枚举变量,只希望为Some时打印消息:
fn main() {
let config_max = Some('e');
let _num:std::option::Option<i32>=None;
match config_max {
Some(max) => println!("The maximum is configured to be {}", max),
_ => (),
}
}
所有不是Some和_的都会直接忽略。
现在我们使用 if let 来重新实现这一实例:
fn main() {
let config_max = Some('e');
if let Some(i)=config_max{
println!("Yes: {}",i);
}
}
可以更加简洁的表示这个实例,就像match的占位符一样,不符合条件的,直接会被省略,这样我们就少写了好多代码。
当然我们也可以使用else:
fn main() {
let config_max:std::option::Option<i32> = None;
if let Some(i)=config_max{
println!("Yes: {}",i);
}else{
println!("None!");
}
}
定义与使用枚举,枚举的绑定与对比结构体的优势,match匹配枚举,match匹配Option枚举,占位符,if let控制流。