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>。这样的设计简化了代码,提高了可读性和可维护性。

相关推荐
9ilk5 分钟前
【同步/异步 日志系统】 --- 前置技术
笔记·后端·其他·中间件
野犬寒鸦28 分钟前
从零起步学习MySQL || 第九章:从数据页的角度看B+树及MySQL中数据的底层存储原理(结合常见面试题深度解析)
java·服务器·数据库·后端·mysql·oracle·1024程序员节
IT_陈寒29 分钟前
SpringBoot 3.2 实战:这5个新特性让你的开发效率提升50%!
前端·人工智能·后端
Victor3561 小时前
Redis(82)如何解决Redis的缓存雪崩问题?
后端
Victor3561 小时前
Redis(83)Redis的缓存击穿是什么?
后端
码事漫谈1 小时前
从LIS到全院区多活:浙江省人民医院“信创样板”全景复盘
后端
Jing_jing_X1 小时前
Spring Boot 启动时,JVM 是如何工作的?
java·后端·spring·1024程序员节
thinktik8 小时前
AWS EKS安装S3 CSI插件[AWS 海外区]
后端·kubernetes·aws
Tony Bai10 小时前
【Go 网络编程全解】12 本地高速公路:Unix 域套接字与网络设备信息
开发语言·网络·后端·golang·unix
fqbqrr10 小时前
2510rs,rust,1.88
rust