Rust特征学习:From和Into特征

本节课我们来看一下与类型转换的有关的两个特征。

在Rust中,FromInto 是两个用于类型转换的特征(traits)。它们允许你在不同类型之间进行转换,提供了一种灵活的方式来处理类型之间的转换。

我们把实现该特征的对象叫实现者。

  1. From特征是将目标对象转换为实现者。
  2. Into特征是将实现者转换为目标对象。
  3. 实现者实现了From特征,目标对象就自动实现Into特征。

From 特征:

From 特征定义了一个用于从一种类型转换为另一种类型的函数。它有一个方法 from,需要实现这个方法来执行类型转换。

rust 复制代码
pub trait From<T>: Sized {
    fn from(value: T) -> Self;
}

例如,假设我们有一个结构体 Person

rust 复制代码
struct Person {
    name: String,
    age: u32,
}

我们可以实现 From 特征来从字符串创建一个 Person

rust 复制代码
impl From<&str> for Person {
    fn from(s: &str) -> Self {
        // s的格式如:"Alice,30"
        let parts: Vec<&str> = s.split(',').collect();
        let name = parts[0].to_string();
        let age = parts[1].parse().unwrap();

        Person { name, age }
    }
}

现在,我们可以使用 from 方法从 &str 类型创建 Person 类型:

rust 复制代码
let person: Person = Person::from("Alice,30");

在标准库中,有一些类似的实现,例如我们经常使用的String::from("oskwg.org")

Into 特征:

Into 特征是与 From 相反的,它定义了一个用于将类型转换为另一种类型的方法 into

rust 复制代码
pub trait Into<T>: Sized {
    fn into(self) -> T;
}

使用上述的 Person 结构体,我们可以实现 Into 特征来将 Person 转换为 String

rust 复制代码
impl Into<String> for Person {
    fn into(self) -> String {
        format!("{} ({} years old)", self.name, self.age)
    }
}

现在,我们可以使用 into 方法将 Person 转换为 String

rust 复制代码
let person = Person { name: "Bob".to_string(), age: 25 };
let person_string: String = person.into();

实现了From特征的类型,自动也实现了 Into 特征

之所以能够自动实现Into特征的原因是如下代码:

rust 复制代码
// src/convert/mod.rs
impl<T, U> Into<U> for T
where
    U: From<T>,
{
    fn into(self) -> U {
        U::from(self)
    }
}

标准库中这段代码的意思是,为T类型实现了Into特征,可以将T类型转换为U类型。where后面限定了U类型,只有实现了From<T>特征的U类型才能转换。

示例:

rust 复制代码
struct User {
    login_name: String,
}
struct Student {
    first_name: String,
    last_name: String,
}

impl From<Student> for User {
    fn from(Student { first_name, last_name }: Student) -> Self {
        User { login_name: format!("{first_name} {last_name}") }
    }
}

// impl Into<User> for Student {
//     fn into(self) -> User {
//        User::from(self)
//     }
// }

fn main() {
    let student = Student { first_name: String::from("oskwg"), last_name: String::from("org") };
    // let user = User::from(student);
    let x: User = student.into();
    println!("{:?}",x)
}

在这个例子中,我们需要把Student转换为User,那么学生就具有了用户登录名,为此我们为User实现了 From<Student>,此时Student类型正好符合了src/convert/mod.rs中泛型的这段代码,所以 Into<User> 也就自动实现了,使得我们可以使用 into 方法进行类型转换,而不必显式实现 Into<User>。这样的设计简化了代码,提高了可读性和可维护性。

相关推荐
AKAMAI2 小时前
微服务架构的核心优势解析
后端·云原生·云计算
你的人类朋友5 小时前
✍️【Node.js程序员】的数据库【索引优化】指南
前端·javascript·后端
why技术9 小时前
翻译翻译,什么叫“编程专用”的显示器?
前端·后端
野生技术架构师10 小时前
SpringBoot集成Tess4j :低成本解锁OCR 图片识别能力
spring boot·后端·ocr
天天摸鱼的java工程师10 小时前
要在 Spring IoC 容器构建完毕之后执行一些逻辑,怎么实现
后端
程序猿小D10 小时前
第25节 Node.js 断言测试
后端·node.js·log4j·编辑器·vim·apache·restful
shengjk111 小时前
一文搞懂 TCP TCP/IP 和 TCP/IP网络分层之间的联系和区别
后端
IT_陈寒11 小时前
一键生成活动页面的智能体开发实践:从策划到分发的全自动化解决方案
人工智能·程序员
述雾学java11 小时前
Spring Boot + Vue 前后端分离项目解决跨域问题详解
vue.js·spring boot·后端