当前位置: 首页 > news >正文

Rust 登堂 之 枚举和整数(八)

整数转换为枚举

在Rust 中,从枚举到整数的类型转换很容易,但是反过来,就没那么容易,甚至部分实现还挺邪恶,例如使用 transmute

一个真实场景的需求

在实际场景中,从整数到枚举的转换有时还是非常需要的,例如你有一个枚举类型,然后需要从外面传入一个整数,用于控制后续的流程走向,此时就需要用整数去匹配相应的枚举(你也可以用整数匹配整数,)

既然有来需求,剩下的就是看看该如何实现,这篇文章的水远比你想象的要深,且看八仙过海各显神通

C语言的实现

对于C 语言来说,万物皆邪恶,因此我们不讨论安全,只看实现,不得不说很讲解

#includ <stdio.h>
enum atomic_number {HYDROGEN = 1,HELIUM = 2,// ...IRON = 26,
};int main(void)
{enum atomic_number element = 26;if (element == IRON) {printf("Beware of Rust!\n");}return 0;
}

但是在Rust中,以下代码

enum MyEnum{A = 1,B,C,
}fn main() {// 将枚举转换成整数,顺利通过let x = MyEnum::C as i32;// 将整数转换为枚举,失败match x {MyEnum::A => {}MyEnum::B => {}MyEnum::C => {}_ => {}}
}

就会报错 MyEnum::A => {} mismatched types ,expected i32 ,found enum MyEnum.

使用三方库

首先可以想到的肯定是三方库,毕竟Rust的生态目前已经发展的很不错,类似的需求总是又得,这里我们先使用 num-traite 和 num-derive 来试试

在 Cargo.toml 中引入

[dependencies]
num-traits = "0.2.14"
num-derive = "0.3.3"

代码如下

use num_derive::FromPrimititve;
use num_traits::FromPrimitive;#[derive(FromPrimitive)]
enum MyEnum{A = 1,B ,C,
}fn main() {let x = 2;match FromPrimitive::from_i32(x) {Some(MyEnum::A) => println!("Got A"),Some(MyEnum::B) => println!("Got B"),Some(MyEnum::C) => println!("Got C"),None            => println!("Couldn't convert {}",x),}
}

除了上面的库,还可以使用一个侥幸的库, num_enums

TryFrom + 宏

在Rust 1.34后, 可以实现TryFrom 特征来做转换

use std::convert::TryFrom;impl TryFrom<i32> for MyEnum {type Error = ();fn try_from(v: i32) -> Result<Self,Self::Error> {match v  {x if x == MyEnum::A as i32 => Ok(MyEnum::A),x if x == MyEnum::B as i32 => Ok(MyEnum::B),x if x == Myenum::C as i32 => Ok(MyEnum::C),_ => Err(()),}}
}

以上代码定义了从 i32 到 MyEnum 的转换,接着就可以使用 TryInfo 来实现转换

use std::convert::TryInto;fn main() {let x = MyEnum::C as i32;match x.try_into() {Ok(MyEnum::A) => println!("a"),Ok(MyEnum::B) => println!("b"),Ok(MyEnum::C) => println!("c"),Err(_) => eprintln!("unknown number"),}
}    

但是上面的代码有个问题,你需要为每一个枚举成员都实现一个转换分支,非常麻烦,好在可以使用宏来简化,自动根据枚举的定义来实现 TryFrom 特征

#[macro_export]
macro_rules! back_to_enum {($(@[$meta:meta]) * $vis:vis enum $name:ident {$($(#[$vmeta:meta]) * $vname:ident $(= $val:expr)?,)*}) => {$(#[$meta])*$vis enum $name {$($(#[$vmeta])* $vname $(= $val)?,)*}impl std::convert::TryFrom<i32> for $name {type Error = ();fn try_from(v: i32) -> Result<Self, Self::Error> {match v {$(x if x == $name::$vname as i32 =>   Ok($name::$vname),)*_ => Err(()),}}}}
}back_to_enum! {enum MyEnum {A = 1,B ,C,}
}

邪恶之王  std::mem::transmute

这个方法原则上并不推荐,但是有其存在的意义,如果要使用,你需要清晰的知道自己为什么使用。

在之前的类型转换章节,我们提到过非常邪恶的 transmute转换,其实,当你知道数值一定不会超过枚举的范围时(例如枚举成员对应 1,2,3,传入的整数也是这个范围内) ,就可以使用这个方法完成变形。

最好使用#[repr(..)] 来控制底层类型的大小。免得本来需要i32 ,结果传入 i64 ,最终内存无法对齐,产生奇怪的结果

#[repr(i32)]
enum MyEnum {A = 1,B,C
}fn main() {let x = MyEnum::C;let y = x as i32;let z: MyEnum = unsafe { std::mem::transmute(y) };// match the enum that came from an int match z {MyEnum::A => { println!("Found A"); }MyEnum::B => { println!("Found B"); }MyEnum::C => { println!("Found C"); }}
}

既然是邪恶之王,当然得有真本事,无需标准库,也无需 unstable 的Rust 版本,

总结

本文例举了常用(其实差不多也是全部了,还有一个 unstable 特性没有提到) 的从整数转换为枚举的方法,推荐度按照出现的先后顺序递减。

但是推荐度最低,不代表它就没有出场的机会,只要使用边界清晰,一样可以大放棺材,例如最后的transmute 函数

http://www.dtcms.com/a/360475.html

相关文章:

  • OpenCL C++ 平台与设备
  • 集合-单列集合(Collection)
  • DrissionPage 实战:动态 IP 代理与百度翻译 API 数据抓取
  • LeetCode算法日记 - Day 27: 计算右侧小于当前元素的个数、翻转对
  • Linux wlan 之网络问题定位分析 实例一
  • 如何确定虚拟机的IP
  • Qt QML连接数据库如何解决重复创建连接问题
  • 【嵌入式】【电机控制】基础知识列表
  • K8s调度核心:从Pod分配到节点优化
  • MATLAB R2010b系统环境(四)MATLAB帮助系统
  • LeetCode 每日一题 2025/8/25-2025/8/31
  • 模拟在线测试六线测试相关知识
  • 如何快速学习新技能
  • io进程线程;标准IO;0831
  • Java全栈开发面试实录:从基础到微服务架构的深度解析
  • Augment 宣布 Auggie CLI正式向所有用户开放
  • 利用DeepSeek编写验证xlsx格式文件中是否启用sharedStrings.xml对读写效率影响python程序
  • Ring Buffer解析
  • Thread、ThreadLocal、ThreadLocalMap
  • 用户态 kill 与 pthread_kill 的区别?
  • 动态链表:结构体模拟单链表的终极指南
  • ts 定义类型
  • Linux学习:简单模拟实现C++中的线程类
  • C++算法学习专题:前缀和
  • 【Linux网络编程】应用层协议-----HTTP协议
  • PostgreSQL表膨胀的危害与解决方案
  • More Effective C++ 条款19:理解临时对象的来源(Understand the Origin of Temporary Objects)
  • centos 7 安装docker、docker-compose教程
  • AI 编程新玩法:用 yunqi-saas-kit 框架制作小游戏,看广告变现轻松赚钱​
  • 国产数据库之TiDB:博采众长