• rust枚举


    一、定义枚举

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

    enum enum_name {
         variant1,
         variant2,
         variant3
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    例如

    enum Fruits {
         Banana, // 香蕉
         Pear, // 梨
         Mandarin, // 橘子
         Eggplant // 茄子
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

    enum Book {
         Papery(u32),
         Electronic(String),
    }
    let book = Book::Papery(1001);
    let ebook = Book::Electronic(String::from("url://..."));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

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

    enum Book {
         Papery { index: u32 },
         Electronic { url: String },
    }
    let book = Book::Papery{index: 1001};
    
    • 1
    • 2
    • 3
    • 4
    • 5

    二、使用枚举

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

    enum_name::variant
    
    • 1

    例如

    let selected = Fruits::Banana;
    let selected: Fruits = Fruits::Banana;
    
    • 1
    • 2

    范例

    #[derive(Debug)]
    enum Fruits {
         Banana, // 香蕉
         Pear, // 梨
         Mandarin, // 橘子
         Eggplant // 茄子
    }
    fn main() {
         let selected = Fruits::Banana;
         println!("{:?}",selected);
    }
    编译运行结果如下
    Banana
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    (二)判断枚举
    只能使用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
    
    • 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

    带属性的枚举

    #[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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    三、标准库枚举

    标准库内置了很多枚举

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

    enum Option {
         Some(T),
         None,
    }
    
    • 1
    • 2
    • 3
    • 4

    它有两个枚举值 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;
    
    • 1
    • 2
    • 3

    如果使用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
    
    • 1
    • 2
    • 3
    • 4
    • 5

    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"); //崩溃
    
    • 1
    • 2
    • 3
    • 4

    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);
    
    • 1
    • 2
    • 3
    • 4

    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);
    
    • 1
    • 2
    • 3
    • 4

    (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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    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);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

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

    enum Result {
         Ok(T),
         Err(E),
    }
    
    • 1
    • 2
    • 3
    • 4

    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");
    
    • 1
    • 2

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5

    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
    
    • 1
    • 2
    • 3
    • 4
    • 5

    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);
             }
         });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    (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);
    
    • 1
    • 2
    • 3
    • 4

    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);
    
    • 1
    • 2
    • 3
    • 4

    (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);
    
    • 1
    • 2
    • 3
    • 4

    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"));
    
    • 1
    • 2
    • 3
    • 4

    (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),
         }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    这种传播错误是如此的常见,以至于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)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

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

    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)
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

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

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

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

    use std::error::Error;
    use std::fs::File;
    fn main() -> Result<(), Box> {
         let f = File::open("hello.txt")?;
         Ok(())
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    PHP超级全局变量:功能、应用及最佳实践
    Nosql inject注入
    嵌入式常用计算神器EXCEL,欢迎各位推荐技巧,以保持文档持续更新,为其他人提供便利
    数据中心网络设计方案,数据中心网络解决方案
    系统分析与设计 复习
    小满nestjs(第十章 nestjs 提供者)
    OpenPCDet系列 | 8.4 nuScenes数据集数据调用和数据分析
    MIT课程分布式系统学习01——Introduction
    聊聊秒杀系统的设计(一)
    Python 网络爬虫:基础与实践
  • 原文地址:https://blog.csdn.net/inxunxun/article/details/133151411