Rust?枚举的使用学习笔记

 更新时间:2024年03月14日 10:25:02   作者:希望_睿智  
Rust中的枚举是一种用户定义的类型,本文主要介绍了Rust枚举的使用,它们不仅仅用于表示几个固定的值,还可以包含函数和方法,具有一定的参考价值,感兴趣的可以了解一下
(福利推荐:【腾讯云】服务器最新限时优惠活动,云服务器1核2G仅99元/年、2核4G仅768元/3年,立即抢购>>>:9i0i.cn/qcloud

(福利推荐:你还在原价购买阿里云服务器?现在阿里云0.8折限时抢购活动来啦!4核8G企业云服务器仅2998元/3年,立即抢购>>>:9i0i.cn/aliyun

概述

Rust中的枚举是一种用户定义的类型,它允许你为一组相关的值赋予友好的名称。在Rust中,枚举是强大的工具,它们不仅仅用于表示几个固定的值,还可以包含函数和方法,使得枚举成员可以有自己的行为。通过与模式匹配和其他Rust特性结合使用,枚举在构建健壮、无崩溃的应用程序中发挥了重要作用,并可大幅提高代码的可读性、可维护性和类型安全性。

基础枚举

在Rust中,枚举通过关键字enum进行声明,它可以包含一组相关的命名常量。比如:我们可以定义一个枚举来表示一周的几天。

enum Day {
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday,
    Sunday,
}

定义好枚举后,我们可以像下面这样使用枚举值。

let cur_day = Day::Wednesday;

关联枚举

Rust中的枚举还可以带有关联值,这使得枚举成员可以有不同的数据类型。比如:我们可以定义一个表示结果的枚举,其中一个成员包含整数值,另一个成员则包含字符串值。

enum Result {
    Ok(i32),
    Err(String),
}

fn main() {
    let success = Result::Ok(66);
    let failure = Result::Err(String::from("failed"));
}

在上面的示例代码中,Result::Ok有一个i32类型的关联值,Result::Err有一个String类型的关联值。

另外,我们还可以为枚举中的属性命名,类似于结构体的语法。但请特别注意:枚举并不能像访问结构体字段那样访问枚举绑定的属性,访问的方法可参考下面的匹配枚举。

enum Shape {
    Point {x: i32, y: i32},
    Rectangle {width: i32, height: i32},
    Circle(i32),
}

fn main() {
    let point = Shape::Point{x: 66, y: 88};
    let rect = Shape::Rectangle{width: 10, height: 20};
    let circle = Shape::Circle(100);
}

匹配枚举

使用match表达式,可以很方便地处理枚举类型的值。Rust强制要求枚举的所有可能变体在match表达式中都被考虑到,以避免未处理的枚举导致的运行时错误。

enum Direction {
    Up(u32),
    Down(i32),
    Left(String),
    Right(String),
}

fn main() {
    let direction = Direction::Up(66);
    match direction {
        Direction::Up(value) => println!("turn up by {}", value),
        Direction::Down(value) => println!("turn down by {}", value),
        Direction::Left(text) => println!("turn left to {}", text),
        Direction::Right(text) => println!("turn right to {}", text),
    }
}

match表达式也可以当作函数表达式来对待,它是可以有返回值的。但有一点需要注意:所有返回值表达式的类型必须一样。

enum Direction {
    Up(u32),
    Down(i32),
    Left(String),
    Right(String),
}

fn convert(direction: Direction) -> u32 {
    match direction {
        Direction::Up(value) => 100,
        Direction::Down(value) => 200,
        Direction::Left(text) => 300,
        Direction::Right(text) => 400,
    }
}

fn main() {
    let value = convert(Direction::Down(99));
    println!("{}", value);
}

在match表达式中,还可以使用通配符,用于对一些特定的值采取特殊操作,而对其他的值采取默认操作。在下面的示例代码中,我们对88和99采取了特殊操作,但对其他值采取了统一的默认处理。

fn main() {
    let value = 66;
    match value {
        88 => println!("conditon 88"),
        99 => println!("conditon 99"),
        other => println!("other conditon {}", other),
    }
}

注意:我们必须将通配分支放在最后,因为模式是按顺序匹配的。如果我们在通配分支后再添加其他分支,Rust在编译时会警告我们“unreachable pattern”,因为此后的分支永远不会被匹配到。

另外,Rust还提供了一种模式:当我们不想使用通配模式获取的值时,可以使用占位符_。这是一种特殊的模式,可以匹配任意值而不绑定到该值。占位符会告诉Rust,我们不会使用这个值,因此Rust也不会警告我们存在未使用的变量。

fn main() {
    let value = 66;
    match value {
        88 => println!("conditon 88"),
        99 => println!("conditon 99"),
        _ => println!("other conditons"),
    }
}

可以看到,对于只有两种匹配情况的场景来说,match显得比较繁琐,必须使用通配符或占位符。为此,Rust提供了语法糖if let,用于简化代码。可以在if let中包含一个else,else块中的代码与match表达式中占位符分支块中的代码相同。

fn main() {
    let value = 66;
    if let 66 = value {
        println!("conditon 66");
    } else {
        println!("other conditons");
    }
}

使用if let,意味着编写更少的代码,但这会失去match强制要求的穷尽性检查(因为else是可选的)。到底该使用match还是if let,取决于我们对增加简洁度和失去穷尽性检查之间的权衡取舍。

Option枚举

Rust中的Option类型是一种枚举,它是Rust语言的核心特性之一,用于处理值可能存在的状态。在许多其他编程语言中,这种场景可能会使用null、None或其他表示空或缺失的特殊值来处理,但这些通常会导致潜在的空引用错误。而Rust通过设计Option<T>类型,强制开发者在编译时就必须考虑值可能不存在的情况,从而保证了运行时的安全性。

Option类型的定义如下:

pub enum Option<T> {
    None,
    Some(T),
}

Option<T>中,T是一个泛型参数,代表了当值存在时的具体类型。这意味着,Option可以包裹任何类型的值。比如:Option<i32>表示可能包含一个整数值,或者没有值。

Option类型提供的主要方法如下。

  • unwrap(): 如果Option是Some(value),则返回该value;如果Option是None,则触发异常。这主要用于开发阶段调试和确定程序逻辑正确的地方,不推荐在生产代码中滥用,因为它会直接终止程序执行。
  • expect(msg): 类似于unwrap(), 但在触发异常时,提供了一个自定义的消息。
  • is_none(): 返回一个布尔值,表示Option是否为None。
  • is_some(): 返回一个布尔值,表示Option是否有值。
  • ok_or(err): 将Option转换成Result,若为Some则映射到Ok(_),若为None则映射到Err(err)。
  • map(f): 如果Option是Some(T),应用函数f给T并返回一个新的Option<T'>(T'是f作用后的新类型)。如果Option是None,则返回None。
  • and_then(f): 类似于map(),但是f必须返回一个Option<T'>,它将链式调用并保持Option的状态。
  • unwrap_or(default): 如果Option是Some,则返回其中的值。否则,返回提供的默认值。
  • unwrap_or_else(f): 类似于unwrap_or(),但当Option为None时,调用函数f生成默认值。

Option类型的具体使用方法,可参考下面的示例代码。

fn divide(a: i32, b: i32) -> Option<i32> {
    if b == 0 {
        None
    } else {
        Some(a / b)
    }
}

fn main() {
    let result = divide(10, 2);
    match result {
        Some(value) => println!("result is: {}", value),
        None => println!("can't be zero"),
    }

    // 当除数非零时,得到结果;否则,返回-1。
    let value = divide(10, 0).unwrap_or(-1);
    println!("value is: {}", value);

    // 使用map进行链式操作,输出: Some(10)
    let number = Some(5);
    let number2 = number.map(|n| n * 2);
    println!("number2 is: {:?}", number2);
}

Option类型在Rust中有着广泛的应用场景,可以用于初始化值、作为函数的返回值、表示简单错误、作为结构体的可选字段等。通过使用Option,我们可以更加明确地处理可能为空的情况,从而避免许多由于空值引起的运行时错误。这也是Rust语言相对于C/C++等语言的一大明显优势。

枚举绑定方法

与结构体类似,Rust的枚举还允许你在枚举成员上定义函数和方法。比如:我们可以给上面的Result枚举添加一个describe方法。

enum Result {
    Ok(i32),
    Err(String),
}

impl Result {
    fn describe(&self) -> &str {
        match self {
            Result::Ok(_) => "Operation was successful",
            Result::Err(_) => "Operation failed",
        }
    }
}

fn main() {
    let success = Result::Ok(42);
    let failure = Result::Err(String::from("something went wrong"));

    println!("{}", success.describe());
    println!("{}", failure.describe()); 
}

使用 Option 枚举处理可能为空的值

在 Rust 中,为了处理可能为空的值,通常使用 Option 枚举类型。Option 类型有两个成员:Some 和 None。Some 成员表示有值的情况,None 成员表示没有值的情况。

以下是一个使用 Option 枚举的示例:

fn divide(dividend: f64, divisor: f64) -> Option<f64> {
    if divisor == 0.0 {
        None
    } else {
        Some(dividend / divisor)
    }
}

fn main() {
    let result = divide(10.0, 2.0);
    
    match result {
        Some(value) => println!("Result: {}", value),
        None => println!("Cannot divide by zero"),
    }
}

在上面的代码中,我们定义了一个名为 divide 的函数,它返回一个 Option<f64> 类型的值。如果除数为零,则返回 None,否则返回 Some 并包含除法运算的结果。

在 main 函数中,我们调用 divide 函数并使用 match 表达式对返回的结果进行模式匹配。如果结果是 Some,则打印结果;如果结果是 None,则打印除数为零的错误消息。

自定义枚举类型

除了使用内置的枚举类型,我们还可以自定义枚举类型。自定义枚举类型允许我们根据特定需求创建自己的数据类型。

以下是一个自定义枚举类型的示例:

enum Fruit {
    Apple,
    Banana,
    Orange,
}

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

在上面的代码中,我们定义了两个自定义枚举类型。Fruit 枚举类型表示水果,有三个成员:Apple、Banana 和 Orange。Result 枚举类型是一个通用的结果类型,有两个类型参数 T 和 E,分别表示成功的结果和错误的类型。Result 枚举类型有两个成员:Ok 和 Err,分别表示成功和失败的情况。

使用自定义枚举类型时,我们可以根据实际需求定义和使用枚举成员,以及处理枚举值的模式匹配。

总结

Rust的枚举提供了一种安全且灵活的方式来处理多种可能的状态和值,使用枚举的优点主要有以下几点。

1、代码清晰性:使用枚举可以使代码更具可读性和可维护性,因为它们为可能的值提供了明确的名称。

2、类型安全:枚举是强类型的,这意味着不能将错误的类型分配给枚举值。

3、灵活性:枚举可以包含关联值,这使得它们能够表示更复杂的数据结构。

4、扩展性:可以在任何时候向枚举添加新的成员,而不会破坏现有的代码。

总之,理解和熟练运用枚举,能够使我们在Rust编程过程中设计出更为简洁、优雅的代码结构。

到此这篇关于Rust 枚举的使用学习笔记的文章就介绍到这了,更多相关Rust 枚举内容请搜索程序员之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持程序员之家!

相关文章

  • Rust 配置文件内容及使用全面讲解

    Rust 配置文件内容及使用全面讲解

    这篇文章主要为大家介绍了Rust 配置文件内容及使用全面讲解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-10-10
  • Rust应用调用C语言动态库的操作方法

    Rust应用调用C语言动态库的操作方法

    这篇文章主要介绍了Rust应用调用C语言动态库,本文记录了笔者编写一个简单的C语言动态库,并通过Rust调用动态库导出的函数,需要的朋友可以参考下
    2023-01-01
  • Rust调用C程序的实现步骤

    Rust调用C程序的实现步骤

    本文主要介绍了Rust调用C程序的实现步骤,包括创建C函数、编译C代码、链接Rust和C代码等步骤,具有一定的参考价值,感兴趣的可以了解一下
    2023-12-12
  • 为什么要使用 Rust 语言、Rust 语言有什么优势

    为什么要使用 Rust 语言、Rust 语言有什么优势

    虽然 Rust 是一种通用的多范式语言,但它的目标是 C 和 C++占主导地位的系统编程领域,很多朋友会问rust语言难学吗?rust语言可以做什么,今天带着这些疑问通过本文详细介绍下,感兴趣的朋友一起看看吧
    2022-10-10
  • Rust自定义安装路径的详细图文教程

    Rust自定义安装路径的详细图文教程

    工欲善其事必先利其器,无论是对小白还是大神来说,想要学习 Rust 第一步那必须是 Rust 的环境配置,下面这篇文章主要给大家介绍了关于Rust自定义安装路径的详细图文教程,需要的朋友可以参考下
    2023-03-03
  • Rust?连接?PostgreSQL?数据库的详细过程

    Rust?连接?PostgreSQL?数据库的详细过程

    这篇文章主要介绍了Rust?连接?PostgreSQL?数据库的完整代码,本文图文实例代码相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-01-01
  • Rust指南枚举类与模式匹配详解

    Rust指南枚举类与模式匹配详解

    这篇文章主要介绍了Rust指南枚举类与模式匹配精讲,枚举允许我们列举所有可能的值来定义一个类型,枚举中的值也叫变体,今天通过一个例子给大家详细讲解,需要的朋友可以参考下
    2022-09-09
  • 利用Rust实现一个简单的Ping应用

    利用Rust实现一个简单的Ping应用

    这两年Rust火的一塌糊涂,甚至都烧到了前端,再不学习怕是要落伍了。最近翻了翻文档,写了个简单的Ping应用练练手,感兴趣的小伙伴可以了解一下
    2022-12-12
  • 详解在Rust语言中如何声明可变的static类型变量

    详解在Rust语言中如何声明可变的static类型变量

    在Rust中,可以使用lazy_static宏来声明可变的静态变量,lazy_static是一个用于声明延迟求值静态变量的宏,本文将通过一个简单的例子,演示如何使用?lazy_static?宏来声明一个可变的静态变量,需要的朋友可以参考下
    2023-08-08
  • Rust中的Iterator和IntoIterator介绍及应用小结

    Rust中的Iterator和IntoIterator介绍及应用小结

    Iterator即迭代器,它可以用于对数据结构进行迭代,被迭代的数据结构是可迭代的(iterable),所谓的可迭代就是这个数据结构有返回迭代器的方法,这篇文章主要介绍了Rust中的Iterator和IntoIterator介绍及应用,需要的朋友可以参考下
    2023-07-07

最新评论

?


http://www.vxiaotou.com