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

相关推荐
小杰来搬砖5 分钟前
讲解instanceof 用法
后端
城里的月光12 分钟前
从900 MB到450 MB:生产中SpringBoot的JVM内存调优技巧
后端
程序员鱼皮31 分钟前
没听说过设计模式?保姆级教程来了!
计算机·程序员·开发·学习路线·自学
Pedantic38 分钟前
为什么 Swift 字符串不能用 `myString[3]` 随便取字符?
前端·后端
liangdabiao42 分钟前
3分钟打造一个无敌的落地页Landing Page - 任何内容都完全自动化
程序员·github
Apifox42 分钟前
提交代码后如何自动触发 Apifox 的自动化测试?
前端·后端·测试
程序员NEO1 小时前
Spring AI 实现让你的 AI “三思而后行”
后端
天下一般1 小时前
go入门 - day1 - 环境搭建
开发语言·后端·golang
程序员NEO1 小时前
Spring AI 骚操作:让大模型乖乖听话,直接返回 Java 对象!
人工智能·后端
星辰大海的精灵1 小时前
FastAPI开发AI应用,多厂商模型使用指南
人工智能·后端·架构