rust - 理解 ToOwned trait

news/2024/10/16 19:23:39/

简介

ToOwned trait支持任意类型的转换,而Clone trait只支持&T 到 T 的转换.以下先介绍一下基本的定义,最后通过一个简单的例子详细理解一下Borrow traitToOwned trait的互相转换的过程.

定义

可以将任意类型T转换为U类型,其中U类型实现了Borrow<T> trait,

  • T: 指的是Self
  • U: 指的是Borrow<Self>

可以简单理解为ToOwned traitBorrow trait反向操作.

pub trait ToOwned {type Owned: Borrow<Self>;fn to_owned(&self) -> Self::Owned;
}

str类型

str已经默认支持了ToOwned trait,如下

impl ToOwned for str {type Owned = String;fn to_owned(&self) -> String {unsafe { String::from_utf8_unchecked(self.as_bytes().to_owned()) }}

可以将str类型转换为String类型,String需要实现 Borrow<str> trait,如下

impl Borrow<str> for String {#[inline]fn borrow(&self) -> &str {&self[..]}
}

下面举一个简单的例子:

#[test]
fn test_string_borrow() {let s = "hello";let t: String = s.to_owned();assert_eq!(t, s.to_string());let s = "world";let t: String = s.to_owned();assert_eq!(t, s.to_string());
}

使用场景

一个班级有多名学生,每个学生有一个唯一的学号,根据学号可以唯一确认这名学生.可以使用 trait 来描述学生和学号之间的关系.

  • 学生类使用Borrow trait 可以实现获取学生的唯一学号.
  • 学号类使用ToOwned trait可以实现根据学号获取学生实例.

通过使用Borrow traitToOwned trait,实现了学生对象和学号对象之间的互转.

下面来看下如何实现这个例子

1. 班级类

使用 HashMap 记录了所有的学生信息.其中 key 表示学号,后续可以通过学号获取学生对象.

#[derive(Debug)]
struct SchoolClass {students: HashMap<String, Rc<Student>>,name: String,
}

2. 学生类

包含了学号类、学生的基本属性、还有所在的班级.如果从数据库约束的角度考虑,可以理解Student中包含了名为班级的外键class.

/// 学生类
#[derive(Debug)]
struct Student {no: StudentNo,                   // 学生编号对象name: String,                    // 学生名称age: u8,                         // 学生年纪class: Rc<RefCell<SchoolClass>>, // 学生所在的班级对象
}

使用Borrow traitStudent类型转换为&StudentNo学号类,如下

impl Borrow<StudentNo> for Student {fn borrow(&self) -> &StudentNo {&self.no}
}

3. 学号类

包含一个唯一的编号值,还需要说明学号属于哪个班级,用于后续从班级中根据学号查询学生.

/// 学生编号类
#[derive(Debug)]
struct StudentNo {no: String,                      // 学生编号值class: Rc<RefCell<SchoolClass>>, // 学生所在的班级
}

使用ToOwned traitStudentNo类型转换为Student类型,如下

/// 根据学生编号值获得对应的学生
impl ToOwned for StudentNo {type Owned = Student;fn to_owned(&self) -> Self::Owned {// 在班级中根据学生编号值查询学生let class = self.class.try_borrow().unwrap();let student = class.fetch_student(&self.no.to_string()).unwrap();// 生成新的学生对象Student {no: StudentNo {no: self.no.clone(),class: Rc::clone(&self.class),},name: student.name.clone(),age: student.age,class: Rc::clone(&self.class),}}
}

4.完整的例子

use std::borrow::Borrow;
use std::cell::RefCell;
use std::collections::HashMap;
use std::fmt;
use std::rc::Rc;#[test]
fn test_to_owned() {/// 学生编号类#[derive(Debug)]struct StudentNo {no: String,                      // 学生编号值class: Rc<RefCell<SchoolClass>>, // 学生所在的班级}/// 根据学生编号值获得对应的学生impl ToOwned for StudentNo {type Owned = Student;fn to_owned(&self) -> Self::Owned {// 在班级中根据学生编号值查询学生let class = self.class.try_borrow().unwrap();let student = class.fetch_student(&self.no.to_string()).unwrap();// 生成新的学生对象Student {no: StudentNo {no: self.no.clone(),class: Rc::clone(&self.class),},name: student.name.clone(),age: student.age,class: Rc::clone(&self.class),}}}/// 学生类#[derive(Debug)]struct Student {no: StudentNo,                   // 学生编号对象name: String,                    // 学生名称age: u8,                         // 学生年纪class: Rc<RefCell<SchoolClass>>, // 学生所在的班级对象}impl fmt::Display for Student {fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {fmt.pad(self.name.as_str())}}impl Borrow<StudentNo> for Student {fn borrow(&self) -> &StudentNo {&self.no}}#[derive(Debug)]struct SchoolClass {students: HashMap<String, Rc<Student>>,name: String,}/// 班级类impl SchoolClass {fn new(name: String) -> Rc<RefCell<SchoolClass>> {Rc::new(RefCell::new(SchoolClass {name: name,students: HashMap::new(),}))}/// 添加学生到班级fn add_student(&mut self, no: String, student: Rc<Student>) {self.students.insert(no, student);}/// 根据学生名称获得学生对象fn fetch_student(&self, no: &String) -> Option<&Rc<Student>> {self.students.get(no)}}impl fmt::Display for SchoolClass {fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {fmt.pad(self.name.as_str())}}// 创建一个班级对象let class_name = "First class";let class = SchoolClass::new(class_name.to_string());// 创建一个学生对象let student_name = "bob";let no = "A001";let student = Student {no: StudentNo { no: no.to_string(), class: Rc::clone(&class) },name: student_name.to_string(),age: 18,class: Rc::clone(&class),};// 添加学生到班级中{class.borrow_mut().add_student(no.to_string(), Rc::new(student));}// 根据学生名称查询学生// Note: 在使用了 std::borrow::Borrow的情况下,注意不能用 class.borrow(), 因为与 RefCell 的 borrow()冲突,所以使用try_borrow()替代let class_a = class.try_borrow().unwrap();let student_bob = class_a.fetch_student(&no.to_string()).unwrap();assert_eq!(student_bob.name, student_name.to_string());// 使用 Borrow trait 获得学生的学号let student = student_bob.as_ref();let student_no: &StudentNo = student.borrow(); // 必须显示标注类型,否则会与默认的 Borrow Trait 冲突assert_eq!(student_no.no, no.to_string());// 使用 ToOwned trait 根据学号获得学生实例let student_bob = student_no.to_owned();assert_eq!(student_bob.name, student_name.to_string());
}

http://www.ppmy.cn/news/1188554.html

相关文章

标题:轻松转换GIF到JPG,批量处理图片,优化你的图片管理!

作为一位设计师或社交媒体工作者&#xff0c;您可能经常需要处理大量的动图或GIF文件。这些GIF文件可能需要进行格式转换&#xff0c;以便更好地满足您的需求。现在&#xff0c;我们向您介绍一款轻松转换GIF到JPG的工具&#xff0c;帮助您更高效地管理您的图片库&#xff01; …

博弈论学习笔记(2)——完全信息静态博弈

前言 这部分我们学习的是完全信息静态博弈&#xff0c;主要内容包括博弈论的基本概念、战略式博弈、Nash均衡、Nash均衡解的特性、以及Nash均衡的应用。 零、绪论 1、什么是博弈论 1&#xff09;博弈的定义 博弈论&#xff1a;研究决策主体的行为发生直接相互作用时候的决策…

PHP判断闰年

闰年的规则 1.能被4整除且不能被100整除 &#xff08;普通闰年&#xff09; 2.能被400整除&#xff0c;公历年份是整百数的&#xff0c;必须是400的倍数才是闰年&#xff08;世纪闰年&#xff09; 代码 function isLeapYear($year) {if($year%40 && $year%100!0){r…

干货!数字IC后端入门学习笔记

很多同学想要了解IC后端&#xff0c;今天大家分享了数字IC后端的学习入门笔记&#xff0c;供大家学习参考。 很多人对于后端设计的概念比较模糊&#xff0c;需要做什么也都不甚清楚。 有的同学认为就是跑跑 flow、掌握各类工具。 事实上&#xff0c;后端设计的工作远不止于此。…

【验证码系列】用逆向思维深度分析滑动验证码(含轨迹算法)

文章目录 1. 写在前面2. 抓包分析3. 接口分析4. 滑动验证码弹出分析5. 滑动验证分析6. 轨迹生成算法实现7. 生成W参数值算法 1. 写在前面 验证码是机器人防护&#xff08;即爬虫&#xff09;常用重要手段之一&#xff01;在爬虫这个领域内专精某一项&#xff08;验证码识别、JS…

思维训练第一课 倒装句

系列文章目录 文章目录 系列文章目录前言一、什么是倒装二、倒装的几种情况1、在以here&#xff0c;there或out&#xff0c;in,up,down,away等小品副词开头的句子里表示强调或修辞需要。但主语是人称代词的时候&#xff0c;主语和谓语的语序不变&#xff0c;当然副词依然放开头…

使用 TensorFlow SSD 网络进行对象检测

使用 TensorFlow SSD 网络进行对象检测 目录 描述这个示例是如何工作的&#xff1f; 处理输入图准备数据sampleUffSSD 插件验证输出TensorRT API 层和操作 先决条件运行示例 示例 --help 选项 附加资源许可证更改日志已知问题 描述 该示例 sampleUffSSD 预处理 TensorFlow …

网管的利器之NMap

在进行网络管理过程中&#xff0c;网管会借助很多的工具比如付费的一些产品&#xff0c;比如漏洞扫描、安全隐患发现、网络设备管理、上网行为管理等。 更多的情况下&#xff0c;网管员使用一些DOS命令或者免费的工具进行&#xff0c;比如前面介绍过的PingInfoView.exe、WinMTR…