enum在实际编程中是非常常用的,enum的目的就是为了清晰定义出散落在系统各个角落的相同概念的有限固定值。

一、enum介绍
如果是简单定义固定值,我们可以使用常量const。比如

public const int MAX_THREAD_COUNT=100;

在C语言中,我们可以这样定义一个枚举方便各处使用,比如:

enum Direction
{
Left,
Center,
Right
}

C#基本继承了C的enum性质,简单无别的,比如:

public enum Week{
  Mon,Tue,Wed,Thu,Fri,Sat,Sun
}

当然可以加点其它,比起C要好一丢丢,然而也仅限于此。以至于当这种简单类型无法满足我们需要要扩展的时候就会使用class/struct来取代写出类似这种代码

public sealed class Error
{
public static readonly SignError=new Error(110,"sign error.");
public static readonly NetworkError=new Error(500,"network is disconnected."); public int code{get;private set;}
public string message{get;private set;} public Error(int code,string message)
{
this.code=code;
this.message=message;
}
}

这也是C#的enum鸡肋的地方。当然这并不是枚举了,只不过到达了相似效果。

接着我们来看Java的enum,就会发现它比较好一些了。还拿上面这个例子来说,比如:

public enum Error
{
SignError(110,"sign error."),NetworkError(500,"network is disconnected."); private int code;
private String message; private Error(int code,String message)
{
this.code=code;
this.message=message;
}
}

这么来看C#的变通enum和Java的原生enum能满足我们大多数的使用场景。

在rust中我们也可以声明类C这样的enum,比如:

pub enum GameState{
Wait,Running,Stop,Reboot
}

rust的enum功效不止于此,我们来看看rust的enum的奇特之处。

二、变体enum(可以当有限泛型用-个人理解)
我们可以把不同数据类型放进一个enum里,比如:

pub enum DbParameterValue<'a> {
Null,
I8(i8),
U8(u8),
I16(i16),
U16(u16),
I32(i32),
U32(u32),
I64(i64),
U64(u64),
F32(f32),
F64(f64),
String(&'a str),
StringArray(&'a [&'a str]),
U8Array(&'a [u8]),
}
pub DbParameter<'a>{
pub name:&'a str,
pub value:&'a DbParameterValue<'a>
}
pub DbSql<'a>{
pub db_parameters: Vec<DbParameter<'a>>,
...
}

  可以看到rust的enum可以支持不同类型,以此到达泛型的效果,我个人把这个称作是有限泛型。
  如果是C#或者Java要实现这个,就只能转换成object,这样必然触发拆箱装箱操作。

三、与match完美配合

let value=DbParameterValue::U8(100);
match value{
DbParameterValue::U8(v)=>println!("{v}"),
...
}

  rust的解构操作可以直接取到实际的值,是不是很优雅。

  其实整个rust体系有两个非常重要的enum:Result和Option。除了所有权和借用规则外,这两个也是保障rust安全的法宝。我们来看看它的定义

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

  Ok(T)表示成功,并且包含返回值, T表示正确的返回值的类型(T为泛型);Err(E)表示失败,并且包含了返回值,E表示错误的返回值的类型(泛型)。

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

  Some(T)表示元组结构体,封装了一个 T 类型的值,None表示无。
  比如下面这个函数:

pub fn divide(a:i32,b:i32)->Result<i32,std::io::Error>{
if b==0{
Err(std::io::Error::new(std::io::ErrorKind::Other, "the divisor must not be ( zero )."))
} else{
Ok(a/b)
}
} pub fn try_divide(a:i32,b:i32)->Option<i32>{
if b==0{
None
} else{
Some(a/b)
}
} fn main(){
if let try_value=try_divide(20,100){
println!("try_value is {try_value}");
} let value=divide(25,0);
match value{
Ok(value)=>println!("{value}"),
Err(e)=>panic!("value is {:?}", error)
}
}

  从调用可以看出,我们在实际函数调用的时候经常都必须针对result和option进行处理,这也就是为什么rust没有空指针的原因,所以说rust从根上是内存安全的。当然社区针对result有更好的解决方式(?操作符配合anyhow)。网上很多例子会unwrap();但是请不要这样做,我们要保持漂亮的代码就应该尽量不使用unwrap,并且标准库中也基本使用?操作符。

四、enum的内存布局

看起来enum这么好,有没有缺点呢,缺点当然是有的,我们写个例子来看看

use std::mem::{size_of,size_of_val};

enum PValue<'a>{
U8(u8),
U64(u64),
String(&'a str),
}
fn main(){
println!("size of PValue:{}",size_of::<PValue>());
println!("size of PValue::u8:{}",size_of_val(&PValue::U8(100)));
println!("size of PValue::u64:{}",size_of_val(&PValue::U64(100)));
println!("size of PValue::str:{}",size_of_val(&PValue::String("hello rust,here's my first rust")));
}

  输出结果

size of PValue:24
size of PValue::u8:24
size of PValue::u64:24
size of PValue::str:24

  

可以看出来,enum的内存大小是以其中最大项的内存来分配的。enum每一项都会有1byte的tag分配,当然rust编译器也有特殊优化,比如针对Option<T>就做了优化,舍弃了1byte的tag分配。

One more thing

很久没写文章了,都有点生疏了,以后还是要多练练,我发现后台插入代码居然没有rust语言可选,希望越来越好吧。

etermparser一个个人开源项目,属于个人兴趣。
https://github.com/bmrxntfj/eterm-parser
由于工作需要解析航信eterm系统返回的数据,目前部分实现了av,detr,fd,ml,pat,pnr等指令的结果解析。
有兴趣可以聊聊交个朋友^_^。

聊一聊Rust的enum的更多相关文章

  1. Rust入坑指南:亡羊补牢

    如果你已经开始学习Rust,相信你已经体会过Rust编译器的强大.它可以帮助你避免程序中的大部分错误,但是编译器也不是万能的,如果程序写的不恰当,还是会发生错误,让程序崩溃.所以今天我们就来聊一聊Ru ...

  2. Rust 阴阳谜题,及纯基于代码的分析与化简

    Rust 阴阳谜题,及纯基于代码的分析与化简 雾雨魔法店专栏 https://zhuanlan.zhihu.com/marisa 来源 https://zhuanlan.zhihu.com/p/522 ...

  3. Enum, Generic and Templates

    文 Akisann@CNblogs / zhaihj@Github 本篇文章同时发布在Github上:https://zhaihj.github.io/enum-generic-and-templat ...

  4. Rust学习之旅(读书笔记):枚举 (Enum)

    Rust学习之旅(读书笔记):枚举 (Enum) C 语言的枚举类型很弱,不如后来的语言,也不如之前的语言.在 C 语言里面枚举量就是一个名字,更方便的定义常量.今天读了<The Rust Pr ...

  5. 聊一聊Java的枚举enum

    一. 什么是枚举 枚举是一种数据类型,具有集合的一些特点,可以存放多个元素,但存储对象有限且固定,枚举也有比较常见的使用场景,如我们需要表达性别(男.女),颜色(红.黄.蓝),星期(星期一.星期二.. ...

  6. Rust入门篇 (1)

    Rust入门篇 声明: 本文是在参考 The Rust Programming Language 和 Rust官方教程 中文版 写的. 个人学习用 再PS. 目录这东东果然是必须的... 找个时间生成 ...

  7. A First Look at Rust Language

    文 Akisann@CNblogs / zhaihj@Github 本篇文章同时发布在Github上:http://zhaihj.github.io/a-first-look-at-rust.html ...

  8. Writing A Threadpool in Rust

    文 Akisann@CNblogs / zhaihj@Github 本篇文章同时发布在Github上:https://zhaihj.github.io/writing-a-threadpool-in- ...

  9. Rust语言学习笔记(7)

    模块 // 兄弟模块 mod network { fn connect() { } } mod client { fn connect() { } } // 父子模块 mod network { fn ...

  10. Tokio,Rust异步编程实践之路

    缘起 在许多编程语言里,我们都非常乐于去研究在这个语言中所使用的异步网络编程的框架,比如说Python的 Gevent.asyncio,Nginx 和 OpenResty,Go 等,今年年初我开始接触 ...

随机推荐

  1. Linux ALSA 核心简单分析

    Linux 内核 ALSA 框架通过向用户空间导出多个设备文件,以使用户空间程序可以与内核的音频子系统交互,可以访问音频硬件设备. Linux 内核 ALSA 音频框架初始化 Linux 内核 ALS ...

  2. OpenLDAP 自助修改密码系统

    一.创建docker-compose文件 root@xx:~# mkdir self-service-password root@xx:~# cd self-service-password root ...

  3. OptiX8入门(一)optixHello

    本人初学者,如有错误和更好的表述,请指出 环境:CLion+VS2022+CUDA Toolkit 12.0.1+OptiX8 下载好后打开SDK就可以看到OptiX官方提供的许多例子,CMake配置 ...

  4. MySQL实战实战系列 00 开篇词 这一次,让我们一起来搞懂MySQL

    你好,我是林晓斌,网名"丁奇",欢迎加入我的专栏,和我一起开始 MySQL 学习之旅.我曾先后在百度和阿里任职,从事 MySQL 数据库方面的工作,一步步地从一个数据库小白成为 M ...

  5. day1项目配置

    项目初始化 本项目使用vite进行构建,vite参考官网 pnpm包管理:performant npm,意味"高性能的npm".pnpm由npm/yarn衍生而来,解决了npmly ...

  6. ISIS 协议常用基本配置总结

    转载请注明出处: 1.创建IS-IS进程,进入IS-IS进程 [Huawei] isis [process-id ] 参数process-id用来指定一个IS-IS进程.如果不指定参数process- ...

  7. 1111error

    Allowed memo ry size of 268435456 bytes exhausted编辑的没有缓存都丢了

  8. 13. 用Rust手把手编写一个wmproxy(代理,内网穿透等), HTTP中的压缩gzip,deflate,brotli算法

    用Rust手把手编写一个wmproxy(代理,内网穿透等), HTTP中的压缩gzip,deflate,brotli算法 项目 ++wmproxy++ gite: https://gitee.com/ ...

  9. 传输层协议:TCP/IP协议,UDP的协议

    传输层: 定义了⼀些传输数据的协议和端口号( WWW 端口 80 等),如:TCP(传输控制协议,传输效率低,可靠性强,⽤于传输可靠性要求⾼,数据量⼤的数据), UDP(⽤户数据报协议,与 TCP 特 ...

  10. 苹果电脑开不了机,mac时间机器备份加速,以及识别不到u盘的方法

    平淡无奇的一天,上班后,我按照正常流程,揭开我亲爱的mac的盖子.屏幕没有如昨天一样照亮我的脸庞,擦,电用完了吗? 我充上电,半小时后,电池都热了,依然开不了机.打售后电话,售后姐姐亲切的指导各种我使 ...