rust枚举

一、定义枚举

1.使用enum关键字定义枚举。
语法格式如下

enum enum_name {
     variant1,
     variant2,
     variant3
}

例如

enum Fruits {
     Banana, // 香蕉
     Pear, // 梨
     Mandarin, // 橘子
     Eggplant // 茄子
}

2.可以为枚举成员添加属性

enum Book {
     Papery(u32),
     Electronic(String),
}
let book = Book::Papery(1001);
let ebook = Book::Electronic(String::from("url://..."));

如果你想为属性命名,可以用结构体语法:

enum Book {
     Papery { index: u32 },
     Electronic { url: String },
}
let book = Book::Papery{index: 1001};

二、使用枚举

(一)使用::
语法格式如下

enum_name::variant

例如

let selected = Fruits::Banana;
let selected: Fruits = Fruits::Banana;

范例

#[derive(Debug)]
enum Fruits {
     Banana, // 香蕉
     Pear, // 梨
     Mandarin, // 橘子
     Eggplant // 茄子
}
fn main() {
     let selected = Fruits::Banana;
     println!("{:?}",selected);
}
编译运行结果如下
Banana

(二)判断枚举
只能使用match语句判断枚举

enum CarType {
     Hatch,
     Sedan,
     SUV
}
fn print_size(car:CarType) {
     match car {
          CarType::Hatch => {
               println!("Small sized car");
          },
          CarType::Sedan => {
               println!("medium sized car");
          },
          CarType::SUV =>{
               println!("Large sized Sports Utility car");
          }
     }
}
fn main(){
     print_size(CarType::SUV);
     print_size(CarType::Hatch);
     print_size(CarType::Sedan);
}
编译运行结果如下
Large sized Sports Utility car
Small sized car
medium sized car

带属性的枚举

#[derive(Debug)]
enum GenderCategory {
     Name(String),
     Usr_ID(i32)
}
fn main() {
     let p1 = GenderCategory::Name(String::from("Mohtashim"));
     let p2 = GenderCategory::Usr_ID(100);
     println!("{:?}",p1);
     println!("{:?}",p2);
     match p1 {
          GenderCategory::Name(val)=> {
               println!("{}",val);
          }
          GenderCategory::Usr_ID(val)=> {
               println!("{}",val);
          }
     }
}
编译运行结果如下
Name("Mohtashim")
Usr_ID(100)
Mohtashim

三、标准库枚举

标准库内置了很多枚举

(一)Option
这个枚举是Option,而且它定义于标准库中,如下:

enum Option {
     Some(T),
     None,
}

它有两个枚举值 None 和 Some(T)。
None 表示可有可无中的无。
Some(T) 表示可有可无中的有,既然有,那么就一定有值,那个T就表示值的类型。

1.定义枚举值
Option 枚举包含在了prelude之中,你不需要将其显式引入作用域。另外,它的成员也是如此,可以直接使用Some和None,不需要加Option:: 前缀。

定义枚举值,可以使用Some(value)或者None。
例子:

let some_number = Some(5);
let some_string = Some("a string");
let absent_number: Option = None;

如果使用None,需要指定Option 是什么类型的,因为编译器只通过None无法推断出Some成员的类型。

当有一个Some值时,我们就知道存在一个值,而这个值保存在Some中。当有个None值时,在某种意义上,它跟空值具有相同的意义:并没有一个有效的值。
那么,Option 为什么就比空值要好呢?
当在Rust中拥有一个像i8这样类型的值时,编译器确保它总是有一个有效的值。我们可以自信使用而无需做空值检查。只有当使用Option的时候需要担心可能没有值,而编译器会确保我们在使用值之前处理了为空的情况。
换句话说,在对Option 进行T的运算之前必须将其转换为T。通常这能帮助我们捕获到空值最常见的问题之一:假设某值不为空但实际上为空的情况。
不再担心会错误地假设一个非空值,会让你对代码更加有信心。为了拥有一个可能为空的值,你必须要显式地将其放入对应类型的Option 中。接着,当使用这个值时,必须明确地处理值为空的情况。只要一个值不是Option 类型,你就 可以 安全地认定它的值不为空。这是Rust的一个经过深思熟虑的设计决策,来限制空值的泛滥以增加Rust代码的安全性。

2.使用枚举
(1)获取some的值
expect
如果是Some,就返回Some的值。如果是None就打印消息,并崩溃。
Panics
如果值为 None 并带有由 msg 提供的自定义panic消息,就会出现panics。
例子

let x = Some("value");
assert_eq!(x.expect("fruits are healthy"), "value");

let x: Option<&str> = None;
x.expect("fruits are healthy"); // `fruits are healthy` 的panics

unwrap
如果是Some,就返回Some的值。如果是None就崩溃。
由于此函数可能会panic,因此通常不建议使用该函数。 应该使用match显式处理None,或者调用unwrap_or,unwrap_or_else,unwrap_or_default。
Panics
如果self的值等于 None,就会出现panics。
例子

let x = Some("air");
assert_eq!(x.unwrap(), "air");
let x: Option<&str> = None;
assert_eq!(x.unwrap(), "air"); //崩溃

unwrap与expect一样,唯一不同是expect能打印自定义消息,而unwrap不能

(2)判断是否有值
is_some
如果选项是 Some 值,则返回 true。
例子

let x: Option = Some(2);
assert_eq!(x.is_some(), true);
let x: Option = None;
assert_eq!(x.is_some(), false);

is_none
如果选项是 None 值,则返回 true。
例子

let x: Option = Some(2);
assert_eq!(x.is_none(), false);
let x: Option = None;
assert_eq!(x.is_none(), true);

(3)逻辑运算
and
如果自己为 None,则返回 None; 否则,返回参数。
例子

let x = Some(2);
let y: Option<&str> = None;
assert_eq!(x.and(y), None);

let x: Option = None;
let y = Some("foo");
assert_eq!(x.and(y), None);

let x = Some(2);
let y = Some("foo");
assert_eq!(x.and(y), Some("foo"));

let x: Option = None;
let y: Option<&str> = None;
assert_eq!(x.and(y), None);

or
如果自己有值,则返回自己,否则返回参数。
例子

let x = Some(2);
let y = None;
assert_eq!(x.or(y), Some(2));

let x = None;
let y = Some(100);
assert_eq!(x.or(y), Some(100));

let x = Some(2);
let y = Some(100);
assert_eq!(x.or(y), Some(2));

let x: Option = None;
let y = None;
assert_eq!(x.or(y), None);

xor
如果自己和参数之一恰好是Some,则返回 Some,否则返回 None。
例子

let x = Some(2);
let y: Option = None;
assert_eq!(x.xor(y), Some(2));

let x: Option = None;
let y = Some(2);
assert_eq!(x.xor(y), Some(2));

let x = Some(2);
let y = Some(2);
assert_eq!(x.xor(y), None);

let x: Option = None;
let y: Option = None;
assert_eq!(x.xor(y), None);

(二)Result
Option枚举返回 None 可以表明失败。但是有时要强调为什么会失败。为做到这点,我们提供了 Result 枚举类型。

enum Result {
     Ok(T),
     Err(E),
}

Result 有两个取值:
Ok(value) 表示操作成功,并包装操作返回的 value(value 拥有 T 类型)。
Err(why),表示操作失败,并包装 why,它能够解释失败的原因(why 拥有 E 类型)。
与Option枚举一样,Result枚举和其成员也被导入到了prelude中,所以就不需要在match分支中的Ok和Err之前加Result::。

1.定义枚举
使用Ok(value)和Err(why)
例子

let ok = Ok(5);
let err = Err("not a string");

2.使用枚举
(1)获取Ok的值
expect
返回包含 self 值的包含的 Ok 值。
由于此函数可能为panic,因此通常不建议使用该函数。 应该使用match显式处理 Err,或者调用 unwrap_or,unwrap_or_else,unwrap_or_default。
Panics
如果值为 Err,就会出现panics,其中panic消息包括传递的消息以及 Err 的内容。
例子

let x: Result = Ok(2);
assert_eq!(x.expect("expect a num"), 2);

let x: Result = Err("emergency failure");
x.expect("Testing expect"); // `Testing expect: emergency failure` 的panics

unwrap
返回包含 self 值的包含的 Ok 值。
由于此函数可能为panic,因此通常不建议使用该函数。 应该使用match显式处理Err,或者调用unwrap_or,unwrap_or_else,unwrap_or_default。
Panics
如果该值为 Err,就会出现Panics,并由 Err 的值提供panic消息。
例子

let x: Result = Ok(2);
assert_eq!(x.unwrap(), 2);

let x: Result = Err("emergency failure");
x.unwrap(); // `emergency failure` 的panics

unwrap_or_else

use std::fs::File;
use std::io::ErrorKind;
fn main() {
     let f = File::open("hello.txt").unwrap_or_else(|error| {
         if error.kind() == ErrorKind::NotFound {
             File::create("hello.txt").unwrap_or_else(|error| {
                 panic!("Problem creating the file: {:?}", error);
             })
         } else {
             panic!("Problem opening the file: {:?}", error);
         }
     });
}

(2)判断是否是ok
is_ok
如果结果为 Ok,则返回 true。
例子

let x: Result = Ok(-3);
assert_eq!(x.is_ok(), true);
let x: Result = Err("Some error message");
assert_eq!(x.is_ok(), false);

is_err
如果结果为 Err,则返回 true。
例子

let x: Result = Ok(-3);
assert_eq!(x.is_err(), false);
let x: Result = Err("Some error message");
assert_eq!(x.is_err(), true);

(3)转换错误
ok
Result 转换为 Option
将 self 转换为 Option,使用 self,并丢弃错误 (如果有)。
Examples

let x: Result = Ok(2);
assert_eq!(x.ok(), Some(2));
let x: Result = Err("Nothing here");
assert_eq!(x.ok(), None);

err
Result 转换为 Option
将 self 转换为 Option,使用 self,并丢弃成功值 (如果有)。
Examples

let x: Result = Ok(2);
assert_eq!(x.err(), None);
let x: Result = Err("Nothing here");
assert_eq!(x.err(), Some("Nothing here"));

(4)函数返回错误,称为传播错误
例子

use std::io;
use std::io::Read;
use std::fs::File;
fn read_username_from_file() -> Result {
     let f = File::open("hello.txt");
     let mut f = match f {
         Ok(file) => file,
         Err(e) => return Err(e),
     };
     let mut s = String::new();
     match f.read_to_string(&mut s) {
         Ok(_) => Ok(s),
         Err(e) => Err(e),
     }
}

这种传播错误是如此的常见,以至于Rust提供了 ?运算符来简化操作。
?运算符用在返回值为Result的表达式后面,它等同于这样一个match表达式:其中Err(err)分支展开成return Err(err),而Ok(ok)分支展开成ok。
例子

use std::io;
use std::io::Read;
use std::fs::File;
fn read_username_from_file() -> Result {
     let mut f = File::open("hello.txt")?;
     let mut s = String::new();
     f.read_to_string(&mut s)?;
     Ok(s)
}

可以在 ? 之后直接使用链式方法调用来进一步缩短代码

use std::io;
use std::io::Read;
use std::fs::File;
fn read_username_from_file() -> Result {
     let mut s = String::new();
     File::open("hello.txt")?.read_to_string(&mut s)?;
     Ok(s)
}

? 运算符只能用于返回Result的函数
下面代码编译错误

use std::fs::File;
fn main() {
     let f = File::open("hello.txt")?;
}

有两种方法修复这个问题。一是将函数返回值类型修改为Result。二是不使用?运算符。
main函数是特殊的,其返回类型是有限制的。main函数的一个有效的返回值是 (),另一个有效的返回值是Result,如下所示:

use std::error::Error;
use std::fs::File;
fn main() -> Result<(), Box> {
     let f = File::open("hello.txt")?;
     Ok(())
}

你可能感兴趣的:(rust,rust,服务器)