首页 > 其他分享 >聊一聊Rust的enum

聊一聊Rust的enum

时间:2023-12-13 14:12:19浏览次数:39  
标签:pub enum value 聊一聊 Rust PValue rust size

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等指令的结果解析。
有兴趣可以聊聊交个朋友^_^。

标签:pub,enum,value,聊一聊,Rust,PValue,rust,size
From: https://www.cnblogs.com/bmrxntfj/p/rust_enum.html

相关文章

  • RustDesk 部署
    一、通过编译好的文件安装1、下载服务端程序wget-P/usr/local/srchttps://github.com/rustdesk/rustdesk-server/releases/download/1.1.9/rustdesk-server-linux-amd64.zip2、解压文件并创建用户#解压tarxf/usr/local/src/rustdesk-server-linux-amd64.zi......
  • 关于Rust的简单总结(一)
    0.前言这是一个关于Rust的简单总结。(待续)资料学习网址:学习Rust-Rust程序设计语言(rust-lang.org)官网:Rust程序设计语言(rust-lang.org)Rust介绍[[Rust]]程序设计语言的本质实际在于 赋能(empowerment):无论你现在编写的是何种代码,Rust能让你在更为广泛的编程......
  • 聊一聊 .NET高级调试 中必知的符号表
    一:背景1.讲故事在高级调试的旅行中,发现有不少人对符号表不是很清楚,其实简而言之符号表中记录着一些程序的生物特征,比如哪个地址是函数(签名信息),哪个地址是全局变量,静态变量,行号是多少,数据类型是什么等等,目的就是辅助我们可视化的调试,如果没有这些辅助我们看到的都是一些无意......
  • dioxus rust 构建跨平台应用的框架
    dioxusrust构建跨平台应用的框架包含的特性原生桌面强大的状态管理快速异步以及协程支持热更新支持对于不同端支持不同的模式 比如桌面支持webassembly的dom处理,ssr等说明目前看dioxus对于开发桌面应用也是一个不错的选择,值得试试,rust周边还是很丰富的参考资......
  • rust 实现图像绕中心点旋转任意角度
    useenv_logger::Env;useimage::RgbaImage;uselog::{info,LevelFilter};usenalgebraasna;usestd::env;usestd::fs::File;usestd::path::Path;usestd::thread::sleep;usestd::time::Duration;fngenerate_matrix(theta:f64,pos:(f64,f64))->na::......
  • 【Cpp 语言基础】简单聊一聊to_string
    头文件:#include<string>功能:将数字常量转换为字符串参数:value返回值:转换好的字符串重载版本:std::stringto_string(intvalue);(1)(C++11起) std::stringto_string(longvalue);(2)(C++11起) std::stringto_string(longlongvalue);(3)(C++11起) std::stringto......
  • yew 基于rust 以及wasm 创建web 应用的框架
    yew基于rust以及wasm创建web应用的框架,我们可以基于一些定好好的rust宏,实现基于webassembly的web应用开发包含的特性基于组件使用了类似rect以及elm的开发模式html宏类似reactjsx的定义ssr支持服务端渲染,默认属于客户端选择,但是可以通过ServerRenderer设......
  • Rusty Tuesday :Rust 基金会一行来访 Databend Labs,共话技术创新!
    在当今快速发展的技术浪潮中,Rust作为一种新兴的编程语言,凭借其卓越的内存安全特性和高效的性能,吸引了全球开发者的广泛关注。2023年12月05日,由DatabendLabs主办的首届RustyTuesday活动正式在北京揭开序幕。在本次活动中,我们非常荣幸地邀请到了多位行业精英:Rust语言......
  • Game = Rust + WebAssembly + 浏览器
    ❝努力成为一个情绪价值的提供者❞大家好,我是「柒八九」。一个「专注于前端开发技术/Rust及AI应用知识分享」的Coder。前言在上一篇Rust编译为WebAssembly在前端项目中使用我们通过一个简单的HelloWorld的Demo,讲述了如何将Rust编译为WebAssembly,并在前端项目中使用。虽然,......
  • switch配合enum的使用
    废话不多说,先上代码,拿性别举个列子。定义一个枚举类publicenumSexEnum{ERROR("0","错误的性别"),MAN("1","男人"),WOMAN("2","女人");Stringcode;Stringname;//枚举被设置成单例的,是不允许new的,所以构造方法默认是private修饰的......