Rust-类型转换进阶

这篇文章收录于Rust 实战专栏。这个专栏中的相关代码来自于我开发的笔记系统。它启动于是2023年的9月14日。相关技术栈目前包括:Rust,Javascript。关注我,我会通过这个项目的开发给大家带来相关实战技术的分享。


关于Rust的类型转换,我在之前的已经感受到了Rust类型的一等公民地位中做了阐述。随着项目进度的推进,对类型转换的使用场景也变得丰富起来。

场景

说到数据转换,在程序开发中是一件很平常的事情,比如,我们下面要讨论的场景
在这里插入图片描述
models::User定义如下:

#[derive(Debug, Deserialize, Serialize)]
pub struct User {pub id: String,pub user_name: String,pub gender: Gender,pub alias: Option<String>,pub birthday_year: Option<u8>,pub birthday_month: Option<u8>,pub birthday_day: Option<u8>,
}

在数据集中,gender的类型是postgres的int not nulltokio_posgres库会将其转换成Rust的i32类型。birthday_year的类型是postgres的int nulltokio_postgres库会自动将其转换成Rust的Option<i32>类型。

因此,我们的目标是

  1. i32转换成models::Gender
  2. Option<i32>转换成Option<u8>

先睹为快,最终的转换应用代码如下

    let row= client.query_one("select id, user_name, alias, gender, birthday_year, birthday_month, birthday_day from users where id=$1", &[id]).await.map_err(MyError::from)?;Ok(User {...gender: SqlGender(row.get("gender")).into(),birthday_year: Sqlu8(row.get("birthday_year")).into(),})

实现步骤

i32 to models::Sex

在这个转换过程中,我们会使用到std::convert::From<T> trait

  1. 声明一个临时类型SqlSex
pub struct SqlGender(pub i32);

之所以要声明这个临时类型,是因为我们要告诉编译器这个tuple接收的数据类型是i32。上面的row.get("gender")的返回实现了FromSql的trait。tokio_postgres通过FromSql实现了对i32的转换。
2. 在models::Gender上实现From<SqlGender>

impl From<SqlGender> for Gender {fn from(val: SqlGender) -> Self {if let Ok(val1) = u8::try_from(val.0) {if let Ok(result) = Gender::try_from(val1) {return result;}}Sex::NotSet}
}

上面的代码,实际上先将i32数据类型转换成u8类型,然后再将u8类型转换成Gender。上面的两个转换过程我们都使用了try_fromtry_from来源于TryFrom trait。其实,如果我们看Rust关于u8的文档,会看见一串From<T>TryFrom<T>的实现。

Option<i32> to Option<u8>

和上面的转不同,这个转换是结果是Option,但由于输入的数据也是一个Option,因此,这里我们还是使用的From<T>。如果转换可能存在失败的情况,且我们要处理失败,那么我们应该使用std::convert::TryFrom<T>

  1. 声明临时类型Sqlu8
pub struct Sqlu8(pub Option<i32>);

声明这个临时类型和上面的原因是一样的,告诉编译器这里使用的是Option<i32>类型。
2. 在Option<u8>上实现From<Sqlu8>

impl From<Sqlu8> for Option<u8> {fn from(val: Sqlu8) -> Self {if let Some(val1) = val.0 {if let Ok(result) = u8::try_from(val1) {return Some(result);}}None}
}

上面的代码先拿到有效的i32数据,然后再将i32转换成u8类型,任何失败都将返回None

转换的应用

实现了上面的步骤,我们通过下面的方式来使用转换。

    let row= client.query_one("select id, user_name, alias, gender, birthday_year, birthday_month, birthday_day from users where id=$1", &[id]).await.map_err(MyError::from)?;Ok(User {...gender: SqlGender(row.get("gender")).into(),birthday_year: Sqlu8(row.get("birthday_year")).into(),})

我们先用声明的临时类型来包裹数据,然后通过调用.into()来实现转换。
Rust本身也有类似的用法,例如将字符串切片转换成String类型。

let msg :String = "hello".into();

这里看起来有没有一点魔幻的感觉,反正我是有的。实现转换的代码和应用转换的代码感觉没啥关联。我查了一下,这是Rust的“关注点分离“设计模式的一种体现。这样设计到好处显而易见,即我们可以无限扩展其类型的转换而不会对已有的代码造成任何影响。例如,我们上面就对i32, u8的转换进行了相关的扩展。

关于临时类型

我们在这里使用临时类型的原因是要告诉编译器,以pub struct Sqlu8(pub Option<i32>);为例,我们要接受一个类型为Option<i32>的值。即相当于一个中间变量。
还有一种情况需要使用临时类型,即如果你要转换的两个类型,都是从第三方模块中引入的,这个时候也需要加入一个临时类型过度。因为Rust不允许转换的两个类型都不在当前模块内。

小结

我们描述了转换的场景,具体的转换步骤和转换的应用方式。这里的场景是数据集和本地类型之间的数据转换。类似的场景还有很多,只要涉及到不同的上下文,数据转换的需求就会出现。使用Rust的std::convert::From<T> trait,实际上就是在实践“关注点分离”的设计模式,它会大大提升我们代码的可维护性和可扩展性,个人认为这是写好Rust代码的重要方法之一。

如有问题,欢迎大家留言交流。关注我,后面会给大家带来更多关于Rust开发实战技术的分享。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/139648.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

软设上午题错题知识点5

软设上午题错题知识点5 1、在ASP的内置对象中。能修改cookie中的值的是response&#xff0c;它还可以创建cookie&#xff0c;而request可以访问cookie中的参数。 2、抽象工厂&#xff08;AbstractFactory&#xff09;模式提供一个创建一系列相关或相互依赖对象的接口&#xf…

基于阿基米德优化优化的BP神经网络(分类应用) - 附代码

基于阿基米德优化优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于阿基米德优化优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.阿基米德优化优化BP神经网络3.1 BP神经网络参数设置3.2 阿基米德优化算…

【vscode下载安装】只需简单一步——使用镜像解决vscode下载慢、失败的问题

vscode下载链接 vscode官网下载&#xff1a;https://code.visualstudio.com 但是下载速度非常慢&#xff0c;还容易下载失败&#xff1a; vscode下载慢、失败的解决方法&#xff1a; 打开下载内容&#xff0c;复制下载链接 粘贴到网址栏&#xff1a; 然后复制 vscode.cdn.az…

ES6 Symbol 数据结构

1. Symbol概念以及引入原因 ES6 引入了的一种新的原始数据类型Symbol&#xff0c;表示独一无二的值。它是 JavaScript 语言的第七种数据类型&#xff0c;前六种是&#xff1a;undefined、null、布尔值&#xff08;Boolean&#xff09;、字符串&#xff08;String&#xff09;、…

ACU-01B 3HNA024871-001/03 机器人将如何改变世界

ACU-01B 3HNA024871-001/03 机器人将如何改变世界 由于改进的传感器技术以及机器学习和人工智能方面更显著的进步&#xff0c;机器人将继续从单纯的机械机器转变为具有认知功能的合作者。这些进步&#xff0c;以及其他相关领域&#xff0c;正在享受一个上升的轨迹&#xff0c;…

计算机缺失pasmutility.dll怎么办,三步解决pasmutility.dll缺失

pasmutility.dll文件是windows系统中重要的dll文件&#xff0c;电脑一旦缺失dll文件就会导致电脑无法正常运行&#xff0c;同时还会唐初电脑缺失pasmutility.dll文件的提示窗口&#xff0c;非常影响电脑运行&#xff0c;那么出现计算机缺失pasmutility.dll该怎么办呢&#xff1…

【硬件+软件】示波器的自动化控制

有没有这样一种情况&#xff0c;就是通过脚本控制你的测量设备&#xff0c;比如示波器&#xff0c;那是不是就可以不用人为的去分析数据&#xff0c;直接由脚本就可以完成整个操作了。 是的&#xff0c;有这样一种方式就可以&#xff0c;就是利用python中的pyvisa库&#xff0c…

Qt系列-常用控件使用整理

1、QMainWindow介绍 菜单栏最多只有一个 //菜单栏创建 菜单栏最多只能有一个QMenuBar*bar menuBar();//将菜单栏放入到窗口中setMenuBar(bar);//创键菜单QMenu*fileMenubar->addMenu("文件");QMenu*editMenubar->addMenu("编辑");//创建菜单项QActi…

牛客网 -- WY28 跳石板

题目链接&#xff1a; 跳石板_牛客题霸_牛客网 (nowcoder.com) 解题步骤&#xff1a; 参考代码&#xff1a; void get_approximate(vector<int>& v,int n) {//求约数&#xff0c;从2到sqrt(n)即可&#xff0c;原因看图解//这里一定要等于sqrt(n)&#xff0c;例如16…

【网络编程】从网络编程、TCP/IP开始到BIO、NIO入门知识(未完待续...)

目录 前言前置知识一、计算机网络体系结构二、TCP/IP协议族2.1 简介*2.2 TCP/IP网络传输中的数据2.3 地址和端口号2.4 小总结 三、TCP/UDP特性3.1 TCP特性TCP 3次握手TCP 4次挥手TCP头部结构体 3.2 UDP特性 四、总结 课程内容一、网络通信编程基础知识1.1 什么是Socket1.2 长连…

Linux C语言

一、基础知识 &#xff08;一&#xff09;冯诺依曼体系 1、存储器&#xff1a;内存 存储程序的思想&#xff1a;按照存储器中指令的顺序 2、存储器的分类 1&#xff09;主存&#xff1a;内存&#xff08;C盘&#xff09; 2&#xff09;外存 3&#xff09;寄存器是cpu内部…

Excel和图片如何互相转换?有何技巧?

一、将图片转为excel表格 首先&#xff0c;打开金鸣识别网站&#xff0c;点击“点击添加需转换的图片或PDF”按钮&#xff0c;添加待识别的图片或PDF文件。 添加完待识别的图片或PDF后&#xff0c;点击“提交识别”按钮&#xff0c;程序便开始识别。 识别完成后&#xff0c;系…