Rust学习之——From Trait和Into Trait以及“类型”到字符串的转换

2024-02-29 10:08

本文主要是介绍Rust学习之——From Trait和Into Trait以及“类型”到字符串的转换,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一次奇怪的实践

今天看了一个demo,为自定义类型到String类型的转换实现了From Trait下的from方法,但是是调用into方法来执行该转换。一开始就觉得很离谱。具体如下所示:

struct OriginType{value: String,
}impl From<OriginType> for TargetType {fn from (t: OriginType) -> TargetType  {省略}
}let o: OriginType = OriginType::new("asdad");
let t: TargetType = o.into();

然后查了资料,发现From和Into这两个Trait是一对,经常在一起出现,但是为什么实现from方法却可以直接用into调用呢?

于是我提出了如下的几个问题:

  1. 为什么可以为类型实现From中的from方法,却用的是从来没有出现过的into方法?
  2. 那么Into Trait是干什么用的?

先回答第一个问题

Used to do value-to-value conversions while consuming the input value. It is the reciprocal of Into.

One should always prefer implementing From over Into because implementing From automatically provides one with an implementation of Into thanks to the blanket implementation in the standard library.

根据官网的描述,From和Into这两个Trait是互为相反的(reciprocal)。并且人们应该更喜欢优先实现From,因为实现From会自动提供Into的实现,这要归功于标准库中的一揽子(blanket)实现。

第二个问题

Only implement Into when targeting a version prior to Rust 1.41 and converting to a type outside the current crate. From was not able to do these types of conversions in earlier versions because of Rust’s orphaning rules. See Into for more details.

Into Trait只在Rust1.41之前,并且用于把一个类型转换为当前crate之外的类型(例如标准库中的Vec或外部库中的类型)。这是因为Rust有孤儿规则,不能去改动外部的,或者说是当前crate之外的类型,而From在早期的版本中无法做到这些类型之间的转换。

Prefer using Into over using From when specifying trait bounds on a generic function. This way, types that directly implement Into can be used as arguments as well.

当在泛型函数上指定Trait bounds时,应该优先使用Into。稍后将在Into的用法中详细介绍。

From Trait

From Trait 用于提供值与值之间的转换(从类型OriginType到另一个类型TargetType)。

pub trait From<T> {fn from(T) -> Self;
}

要为TargetType实现From,必须实现的方法是from。看下面的一个例子:

impl From<OriginType> for TargetType {fn from(value: OriginType) -> Self {// pass// 返回一个TargetType的实例}
}let o: OriginType;
// 这两种方法都可以,第一种方法可以自动推断类型,因此不需要类型注解
// 第二种方法由于使用了into方法,而且一个类型可以转换为多个其他类型,因此必须进行类型注解
let t = TargetType::from(o);
let t: TargetType = o.into();

实例:下面的代码片段就是从字符串的HTTP请求 转换为 为带有数据结构的、便于查询的HttpRequest的结构体类型。

impl From<String> for HttpRequest {fn from (req: String) -> Self {return HttpRequest {method: parsed_method(req),resource: parsed_resource(req),version: parsed_version(req),headers: parsed_headers(req),body: parsed_body(req),}}
}let req_string: String = String::from_utf8(read_buffer.to_vec()).unwrap();
// 有两种方法第一种是实现的from方法,第二种是自动对应的Into实现的into方法
// 第一种方法可以自动推断类型,因此可以不写类型注解
// 第二种方法使用了into方法,而且一个类型可以转换为多个其他类型,因此必须进行类型注解
let http_request = HttpRequest::from(req_string);
let http_request: HttpRequest = req_string.into();

再说Into Trait

之前说了,在Rust1.41之前,如果目标类型不是当前crate中的一部分,那么不能直接实现From方法,例如使用以下的代码:

在下面的代码片段中,Wrapper是一个自定义的元组结构体,用于存放类型T的向量,而目标类型Vec<T>是标准库中的类型。

struct Wrapper<T>(Vec<T>);impl<T> From<Wrapper<T>> for Vec<T> {fn from(w: Wrapper<T>) -> Vec<T> {w.0}
}

这段代码在旧版本中会编译失败,这是因为Rust的孤儿规则曾经更严格一些。要绕过这个,可以尝试实现Into:

impl Into<TargetType> for OriginType {fn into(value: OriginType) -> TargetType {// 返回TargetType类型的值}
}
struct Wrapper<T>(Vec<T>);impl<T> Into<Vec<T>> for Wrapper<T> {fn into(self) -> Vec<T> {self.0}
}

重要的是要了解 Into 不提供 From 实现( From 却提供 Into)。因此,应该始终尝试先实现 From,如果 From 无法实现,则再尝试使用 Into

标准库中的String类型就实现了Into<Vec<u8>>:is_hello的参数表示可以接收任意一个能够转换为Vec<u8>的类型。

fn is_hello<T: Into<Vec<u8>>>(s: T) {let bytes = b"hello".to_vec();assert_eq!(bytes, s.into());
}let s = "hello".to_string();
is_hello(s);

注意事项

From和Into实现的转换不允许出现错误,即转换过程不能抛出异常。如果转换过程允许抛出异常请使用:TryFrom和TryInto。

这篇关于Rust学习之——From Trait和Into Trait以及“类型”到字符串的转换的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/758409

相关文章

MySQL 字符串截取函数及用法详解

《MySQL字符串截取函数及用法详解》在MySQL中,字符串截取是常见的操作,主要用于从字符串中提取特定部分,MySQL提供了多种函数来实现这一功能,包括LEFT()、RIGHT()、SUBST... 目录mysql 字符串截取函数详解RIGHT(str, length):从右侧截取指定长度的字符SUBST

Python将字符串转换为小写字母的几种常用方法

《Python将字符串转换为小写字母的几种常用方法》:本文主要介绍Python中将字符串大写字母转小写的四种方法:lower()方法简洁高效,手动ASCII转换灵活可控,str.translate... 目录一、使用内置方法 lower()(最简单)二、手动遍历 + ASCII 码转换三、使用 str.tr

Java如何将文件内容转换为MD5哈希值

《Java如何将文件内容转换为MD5哈希值》:本文主要介绍Java如何将文件内容转换为MD5哈希值的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java文件内容转换为MD5哈希值一个完整的Java示例代码代码解释注意事项总结Java文件内容转换为MD5

使用Java将实体类转换为JSON并输出到控制台的完整过程

《使用Java将实体类转换为JSON并输出到控制台的完整过程》在软件开发的过程中,Java是一种广泛使用的编程语言,而在众多应用中,数据的传输和存储经常需要使用JSON格式,用Java将实体类转换为J... 在软件开发的过程中,Java是一种广泛使用的编程语言,而在众多应用中,数据的传输和存储经常需要使用j

Java实现视频格式转换的完整指南

《Java实现视频格式转换的完整指南》在Java中实现视频格式的转换,通常需要借助第三方工具或库,因为视频的编解码操作复杂且性能需求较高,以下是实现视频格式转换的常用方法和步骤,需要的朋友可以参考下... 目录核心思路方法一:通过调用 FFmpeg 命令步骤示例代码说明优点方法二:使用 Jaffree(FF

Java如何用乘号来重复字符串的功能

《Java如何用乘号来重复字符串的功能》:本文主要介绍Java使用乘号来重复字符串的功能,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java乘号来重复字符串的功能1、利用循环2、使用StringBuilder3、采用 Java 11 引入的String.rep

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示

C语言中的常见进制转换详解(从二进制到十六进制)

《C语言中的常见进制转换详解(从二进制到十六进制)》进制转换是计算机编程中的一个常见任务,特别是在处理低级别的数据操作时,C语言作为一门底层编程语言,在进制转换方面提供了灵活的操作方式,今天,我们将深... 目录1、进制基础2、C语言中的进制转换2.1 从十进制转换为其他进制十进制转二进制十进制转八进制十进

rust 中的 EBNF简介举例

《rust中的EBNF简介举例》:本文主要介绍rust中的EBNF简介举例,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. 什么是 EBNF?2. 核心概念3. EBNF 语法符号详解4. 如何阅读 EBNF 规则5. 示例示例 1:简单的电子邮件地址

Pandas进行周期与时间戳转换的方法

《Pandas进行周期与时间戳转换的方法》本教程将深入讲解如何在pandas中使用to_period()和to_timestamp()方法,完成时间戳与周期之间的转换,并结合实际应用场景展示这些方法的... 目录to_period() 时间戳转周期基本操作应用示例to_timestamp() 周期转时间戳基