【Rust标准库中的convert(AsRef,From,Into,TryFrom,TryInto)】

Rust标准库中的convert(AsRef,From,Into,TryFrom,TryInto)

  • 为什么需要convert库
  • AsRef(不可变引用:多用于内部字段获取值)
  • From/Into Trait | TryFrom/TryInto Trait
      • From Trait:
      • TryFrom Trait:
    • From代码示例
    • Into使用方法示例
  • 总结


为什么需要convert库

在程序设计时,开发者一般会选择将一系列类型数据打包在一起,并有所限制,一是为了代码的简洁美观和复用,二是为了给予字段访问限制(如我们只通过初始化函数赋予字段值,外部程序需要引用到内部字段但不该修改它)
提到限制,会有开发者想到使用pub 关键字,没错,pub关键字可以将内部字段暴露给外部函数,但是破坏了封装性,且没有限制可变性,有人说我们可以自己写一个函数,也Ok,但是需要注意可变性的限制 ,一般情况下,我们都不希望外部程序可以通过除特定的方法之外修改我们的字段值。
Rust为开发者提供了一揽子转换方法,不论是从基础转为派生,还是反向转换均有trait,使用者只需实现trait,便可使用其中的转换方法并不失去封装性。

AsRef(不可变引用:多用于内部字段获取值)

假设有这样一种需求,某论坛需要获取登陆者的电话号码,以便在后续论坛举办活动时给会员发去活动邀请,所以我们就需要挑选合适的方式在代码中储存信息以及分析合理性。

  1. 我们需要一个struct元组来描述用户的电话号码(这里涉及到新类型模式,不展开了,仅以简单示例):
//UserInfo.rs
#[derive(Debug)]
pub struct Phone(String);
//我们实现了简单的new函数,并包含简单的号码正确性验证。
impl Phone {pub fn new(phone_number: &str) -> Result<Self, &'static str> {if phone_number.len() == 11 {Ok(Self(phone_number.to_string()))} else {Err("Invalid phone number")}}
}
//并将其封装到包mod.rs
pub(crate) mod UserInfo;

2.我们在main.rs,写一个sendmsg方法用以表示发送短信通知:

mod user_info;
use std::error::Error;use user_info::UserInfo::Phone;fn sendmsg(phonenum: &str) -> Result<String, Box<dyn Error>> {// Simulate a call to the phone number// For simplicity, we just return the number as a stringOk(phonenum.to_string())
}
fn main() {let result = Phone::new("13324533333");match result {Ok(phone) => sendmsg(phone.0),Err(e) => todo!(),};
}
//哪里会有问题?

没错,在sendmsg(phone.0) 时会有如下报错,field 0 of Phone is private
不论是将Phone中的String设置为pub,还是使用可变引用都破坏了我们代码的封装性。

正确地方法:实现trait AsRef:

//在UserInfo.rs中添加如下实现
impl AsRef<str> for Phone {fn as_ref(&self) -> &str {&self.0}
}//main.rs中使用入下调用
let result: Result<Phone, &str> = Phone::new("13324533333");let _ = match result {Ok(phone) => sendmsg(phone.as_ref()),Err(_e) => todo!(),};

如此,我们既不破坏封装性,又可以使用Rust convert的系列方法。

From/Into Trait | TryFrom/TryInto Trait

用以值到值的转换,简单来说,From提供细分内部类型向外部总类型转换,Into可以理解为为了适配孤儿规则而存在的,当前的版本1.82.0一般情况下不会有人主动实现Into,由于Rust的一揽子trait ,实现了From就等于实现了Into,非常方便。
不论是实际应用上,还是Rust中的举例来讲,From确实非常适合工程下的错误处理。
From有如下特点:

  1. 涉及到的转换不可以失败。
  2. 转换必须无损,如不丢失数据
  3. 转换必须保值,即不丢失精度
  4. 必须式是显而易见的转换,如 AuthError—> ServerError
//仅作代码示例
#[derive(Debug)]
enum ServerError {//总类型DatabaseError(String),//细分类型NetworkError(std::io::Error),TimeoutError(VarError),AuthError(Error),
}

ps: 如果不符合上述,则需要使用TryFrom,同样的,实现了TryFrom等于实现了TryInto。

From Trait:

pub trait From<T>: Sized {// Required methodfn from(value: T) -> Self;
}
//其直接返回类型。

TryFrom Trait:

pub trait TryFrom<T>: Sized {type Error;// Required methodfn try_from(value: T) -> Result<Self, Self::Error>;
}
//其返回Result,允许失败。

From代码示例

use std::{env::VarError,fmt::{Display, Error},
};
//仅作代码示例
#[derive(Debug)]
enum ServerError {DatabaseError(String),NetworkError(std::io::Error),TimeoutError(VarError),AuthError(Error),
}
impl Display for ServerError {fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {match self {ServerError::DatabaseError(err) => write!(f, "Database error: {}", err),ServerError::NetworkError(err) => write!(f, "Network error: {}", err),ServerError::TimeoutError(err) => write!(f, "Timeout error: {}", err),ServerError::AuthError(err) => write!(f, "AuthError error: {}", err),}}
}
impl From<String> for ServerError {fn from(err: String) -> Self {ServerError::DatabaseError(err)}
}impl From<std::io::Error> for ServerError {fn from(err: std::io::Error) -> Self {ServerError::NetworkError(err)}
}
impl From<Error> for ServerError {fn from(err: Error) -> Self {ServerError::AuthError(err)}
}impl From<VarError> for ServerError {fn from(err: VarError) -> Self {ServerError::TimeoutError(err)}
}fn handle_server_error() -> Result<(), String> {Err(String::from("handle_server_error"))
}
fn handle_server_error1() -> Result<(), std::io::Error> {Ok(())
}
fn handle_server_error2() -> Result<(), VarError> {Ok(())
}
fn handle_server_error3() -> Result<(), Error> {Ok(())
}fn func() -> Result<(), ServerError> {handle_server_error()?;handle_server_error1()?;handle_server_error2()?;handle_server_error3()?;Ok(())
}fn main() {match func() {Ok(_) => println!("Success"),Err(e) => eprintln!("Error: {:?}", e),}
}

如此,开发者既可以细分错误类型,并定制化输出内容,又可以统一result类型,并使用【?】将error向上抛出
同时,Rust也提供了thiserror,anyhow等错误处理包,通过扩展宏标记后,会生成大部分的样板代码,同时通过trace等方式,将上下文串联起来更加方便的排查问题。

Into使用方法示例

此示例代码来源于Rust By Example

use std::convert::Into;#[derive(Debug)]
struct Number {value: i32,
}impl Into<Number> for i32 {fn into(self) -> Number {Number { value: self }}
}fn main() {let int = 5;// Try removing the type annotationlet num: Number = int.into();println!("My number is {:?}", num);
}

总结

Rust中的转换,不仅仅使用方便,更重要的是可以告知阅读者我们在做什么。

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

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

相关文章

自扶正救生艇,保障水上救援的安全卫士_鼎跃安全

在应急事件中&#xff0c;自扶正救生艇能够发挥关键的救援和保障作用&#xff0c;确保救援人员和被困人员的生命安全&#xff0c;尤其在极端天气或突发水上事故中展现出明显优势。 在救援过程中如果遭遇翻船&#xff0c;救生艇能够迅速恢复正常姿态&#xff0c;确保救援人员不会…

提升网站安全性 HTTPS的重要性与应用指南

内容概要 在如今数字化快速发展的时代&#xff0c;网站安全显得尤为重要。许多用户在访问网站时&#xff0c;尤其是涉及个人信息或金融交易时&#xff0c;对数据传输的安全性有着高度的关注。HTTPS&#xff08;超文本传输安全协议&#xff09;正是为了满足这种需求而诞生的。通…

QT——自定义控件绘图

一.QPaintEvent绘图事件 QPaintEvent是QT中一个重要的类&#xff0c;专门用于绘图事件。当QT视图组件需要重绘制自己的一部分时&#xff0c;就会产生该事件&#xff0c;通常发生在以下几种情况。 窗口第一次显示时&#xff1a;当窗口或控件第一次出现在屏幕中&#xff0c;系统…

【jvm】Minor GC

目录 1. 说明2. JVM内存结构2.1 年轻代2.2 老年代2.3 永久代/元空间 3. 工作原理4. 触发条件5. 影响6. 优化策略 1. 说明 1.minor是较小的、较少的、次要的含义。2.在Java虚拟机中&#xff0c;Minor GC是指针对于年轻代&#xff08;Young Generation&#xff09;进行的垃圾回收…

【Python · Pytorch】人工神经网络 ANN(上)

【Python Pytorch】人工神经网络 ANN&#xff08;上&#xff09; 0. 生物神经网络1. 人工神经网络定义2. 人工神经网络结构2.1 感知机2.2 多层感知机2.3 全连接神经网络2.4 深度神经网络 2. 训练流程※ 数据预处理 (Data Preprocessing) 3. 常见激活函数3.1 Sigmoid / Logisti…

【Redis_Day2】在Linux中安装Redis5

本篇涉及Linux中的三条指令&#xff1a;su&#xff1b;apt&#xff1b;vim&#xff0c;可以了解后再来浏览本篇。或在评论留言。 【Redis_Day2】在Linux中安装Redis5 安装修改配置文件使用redis-cli连接服务器 安装 Linux版本选择Ubuntu22.04 Redis版本选择Redis5 登录Ubunt…

第1篇 引言

一、AIGC概念 1、AIGC定义 AIGC&#xff0c;即生成式人工智能&#xff08;Artificial Intelligence Generated Content&#xff09;&#xff0c;是指利用人工智能技术自动生成或辅助创作内容的过程和结果。 简单来说&#xff1a;过去&#xff0c;写文章、画张图、唱首歌、弄个…

深度学习---------------------------------Transformer

目录 Transformer架构多头注意力有掩码的多头注意力基于位置的前馈网络层归一化信息传递预测总结代码多头注意力使用多个头并行计算选择缩放点积注意力作为每一个注意力头测试该部分总代码Transformer基于位置的前馈网络改变张量的最里层维度的尺寸对比不同维度的层归一化和批量…

世界时区划分

1. AoE &#xff08;Anywhere on Earth&#xff09;代表地球上最后一个时区的时间&#xff0c;是全球范围内最晚的时间&#xff0c;通常用于截止日期。 2. UTC/GMT &#xff08;协调世界时/格林威治时间&#xff09;是全球的标准时间&#xff0c;所有时区都是基于UTC计算的。…

qt QImage详解

1、概述 QImage是Qt框架中用于处理图像数据的一个核心类。与QPixmap不同&#xff0c;QImage是在内存中直接存储图像像素数据的&#xff0c;这使得它适用于需要直接访问和修改像素的应用场景&#xff0c;比如图像处理算法、图像绘制以及图像分析等。QImage支持多种图像格式&…

将分类标签转换为模型可以处理的数值格式

将分类标签转换为模型可以处理的数值格式是数据预处理的关键步骤&#xff0c;尤其是在处理监督学习任务时。以下是几种常用的方法&#xff0c;每种方法都有其特点和适用场景&#xff1a; 1. Label Encoding&#xff08;标签编码&#xff09; 原理&#xff1a; 标签编码将每个…

DAY75WEB 攻防-验证码安全篇接口滥用识别插件复用绕过宏命令填入滑块类

知识点&#xff1a; 1、验证码简单机制-验证码过于简单可爆破 2、验证码重复使用-验证码验证机制可绕过 3、验证码智能识别-验证码图形码被可识别 4、验证码接口调用-验证码触发接口可枚举 图片验证码-识别插件-登录爆破&接口枚举 验证码识别绕过等技术适用于&#x…

15分钟学 Go 第 32 天:基本调试技巧

第32天&#xff1a;基本调试技巧 在Go语言的开发过程中&#xff0c;调试是确保代码质量的重要环节。通过有效的调试技巧和工具&#xff0c;开发者可以快速定位和修复问题&#xff0c;从而提高开发效率。今天的学习目标是掌握Go语言中的基本调试工具和技巧。 1. 调试的必要性 …

字符串左旋 (干货无废话)

题目内容&#xff1a;实现一个函数&#xff0c;可以左旋字符串中的k个字符 例如&#xff1a;ABCD左旋一个字符得到BCDA ABCD左旋两个字符得到CDAB 画图解释&#xff1a; 上图分别是向左挪1次&#xff0c;2次&#xff0c;3次&#xff0c;4次&#xff0c;5次后的结果…

QML基础语法2

函数 函数格式&#xff1a; function关键字 函数名(参数名1:参数类型,参数名2:参数类型,...):返回值类型{} 其中&#xff1a; 函数名必须以小写字符开头&#xff0c;后面驼峰可以有多个参数或者没有参数参数类型可以不写返回值类型也可以不写 如何调用&#xff1a;通过id点…

Mac 配置SourceTree集成云效

1、背景 工作使用的是自己的笔记本&#xff0c;一个是比较卡&#xff0c;在一个是敏感信息比较多还是使用公司的电脑&#xff0c;但是系统是Mac就很麻烦&#xff0c;在网上找了帖子记录一下 2、配置 打开终端 ssh-keygen -t rsa #一直回车就行 cd .ssh cat id_rsa.pub #查…

Kubernetes中常见的volumes数据卷

华子目录 volumesk8s支持的卷的类型emptyDir卷功能emptyDir的使用场景示例 hostPath卷功能用法安全隐患示例 nfs卷功能应用示例&#xff1a;部署一台nfs服务器并在所有k8s节点中安装nfs-utils volumes 容器中文件在磁盘上是临时存放的&#xff0c;这给容器中运行的特殊应用程序…

PaddleNLP的FAQ问答机器人

项目源码获取方式见文章末尾&#xff01; 600多个深度学习项目资料&#xff0c;快来加入社群一起学习吧。 《------往期经典推荐------》 项目名称 1.【DDRNet模型创新实现人像分割】 2.【卫星图像道路检测DeepLabV3Plus模型】 3.【GAN模型实现二次元头像生成】 4.【CNN模型实…

【博弈论】分割数游戏

题目描述 有一天 bb和dd玩游戏 你需要帮他们求出每局的胜败情况。 游戏规则是这样的&#xff1a; 每次一个人可以对给出的数进行分割&#xff0c;将其割成两个非零自然数之后&#xff0c;由另一个人选择留下两个数中的其中一个并进行分割剩下的一个数&#xff0c;重复步骤………

发布 NPM 包时,终端显示发布成功但实际上版本并没有更新,可能是由于以下原因

如果发布仍然没有生效&#xff0c;可以检查以下几点&#xff1a; 版本号是否更新&#xff1a; 如果版本号没有更新&#xff0c;NPM 会拒绝发布新的包版本。运行以下命令以确保版本号增加了&#xff1a; bash 复制代码 npm version patch # 更新小版本号 正确的 NPM 注册表&a…