前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【Rust笔记】从·类型转换·视角,浅谈Deref<Target = T>, AsRef<T> 等差异

【Rust笔记】从·类型转换·视角,浅谈Deref<Target = T>, AsRef<T> 等差异

作者头像
MikeLoveRust
发布2022-11-28 15:23:22
3440
发布2022-11-28 15:23:22
举报
文章被收录于专栏:Rust语言学习交流

【原创】从·类型转换·视角,浅谈Deref<Target = T>, AsRef<T>, Borrow<T>From<T> trait差异

概述

这些trait的共同作用就是“类型转换”,但它们“类型转换”的内容各有不同:

  • Deref<Target = T> / DerefMut<Target = T> trait — 从一个类型的引用&F至另一个类型的引用&T的类型转换。
    • 这类·类型转换·有一个专有名词:【智能指针】的【自动·解引用】。
    • Deref / DerefMut仅能被同一个类型至多实现一次。所以,任何类型仅能作为另一个类型(而不是多个类型)的智能指针。
  • AsRef<T> / AsMut<T> trait — 从一个类型F至另一个类型的引用&T的类型转换
    • 不同于Deref / DerefMutAsRef / AsMut可以被同一个类型实现多次,且每次都指定不同的【泛型·类型实参】。所以,若抛开【智能指针】的语义,任何类型都能作为另外多个类型的引用。
  • Borrow<T> / BorrowMut<T> trait — 是AsRef<T> / AsMut<T> trait的加强版本。
    • 除了从·类型F·至·引用&T·的类型转换,它还要求【类型转换·源类型】与【类型转换·目标类型】以一致的“行为”实现EqHashOrd三个trait。这样【源·类型】与【目标·类型】就备有相同的【判等·标准】。
  • From<T> trait — 从一个类型T至另一个类型F的类型转换。
    • 消费掉【类型转换·源类型】的所有权的。
    • 使用【源·类型】的pub数据,构造一个崭新的【类型转换·目标类型】实例

如何给【自定义·类型】实现这些trait

总结起来,有两类套路:

  • 套路一:源类型·包装器
    • Deref<Target = T> / DerefMut<Target = T> trait
    • AsRef<T> / AsMut<T> trait
    • Borrow<T> / BorrowMut<T> trait
    • trait被实现于【类型转换·源类型】
    • 【源·类型】作为【容器·类型】;【类型转换·目标类型】作为容器的【内部·数据类型】(比如,字段·或·元素)
    • 【源·类型】拥有【目标·类型】的【所有权】。所以,仅能从【源·类型】的trait成员方法取得【目标·类型】的引用
    • 【源·类型】提供【目标·类型】不具备的额外功能或语义 — 智能指针
    • 特点 [例程1]
    • 符合这个套路的trait包括
  • 套路二:目标类型·构造器
    • From<T> trait
    • trait被实现于【类型转换·目标类型】
    • 以消费掉【类型转换·源类型】实例的【所有权】为代价,创建一个崭新的【目标·类型】实例。
    • 特点 [例程2]:
    • 符合这个套路的trait包括

如何触发这些trait引导的【类型转换】?

总结起来,也有两类套路:

  • 不需要【泛型·编程】,由编译器来隐式引导【类型转换】
    • rustc会自动给类型F实现Into<T> trait。于是,就有<F, T> where T: From<F>, F: Into<T>。其中,F: Into<T>是被编译器“买一送一”的。
    • F可被显示地类型转换至T [例程4],仅需要显示调用Ftrait成员方法<F as Into>::into(_: F)
    • F就是T的【智能指针】— 给普通【引用】赋能了·额外的自定义功能·和保存了·更多状态信息·
    • &F可被隐式地“类型转换”为&T[例程3] — 不需要任何额外的编码,因为【自动·解引用】。
    • 【类型转换·源类型】之所以是&F(而不是F)是因为【解引用】必须以【引用&F】为起点,而不是【所有权·变量F】。
    • <F, T> where F: Deref<Target = T>,那么
    • <F, T> where T: From<F>,那么
  • 需要【泛型·编程】来引到【类型系统】完成【类型转换】
    • F可被显示地“类型转换”为&T[例程6],需要
    • 同时要求:F&T一致的行为实现了EqHashOrd三个trait。即,若x.borrow() == y.borrow(),就意味着x == y。反之亦然。
    • Borrow<T>出现于【泛型·代码】内和作为【泛型·类型参数】的trait限定条件。
    • 调用F的成员方法<F as Borrow>::borow(_: &F)
    • F可被显示地“类型转换”为&T[例程5],需要
    • AsRef<T>出现于【泛型·代码】内和作为【泛型·类型参数】的trait限定条件。
    • 调用Ftrait成员方法<F as AsRef>::as_ref(_: &F)
    • <F, T> where F: AsRef<T>,那么
    • <F, T> where F: Borrow<T>,那么

这些trait的常见使用场景

场景一

模仿OOP中的函数重载。即,让同一个函数

  • 不但,能够接受不同“形状”的实参来"兑现"形参
  • 还要,以一致的行为完成相同的任务。

就是模仿得不是很彻底。

场景二

HashMap<K, V>添加新【键-值对】和从HashMap<K, V>检索已有的【键-值对】。

  • 作为【集合·类型】,HashMap<K, V>需要拥有它的【集合·元素】std::collections::hash_map::Entry的所有权。所以,HashMap::insert(_: K, _: V)成员方法要求【键】与【值】的所有权·变量。
  • HashMap<K, V>查询检索过程中,对【键】数据的所有权要求就可以忽略了,因为这可以避免潜在的【堆】分配和提高程序性能。但是,为了确保搜索结果的一致性,【键】数据的 必须具备相同的【判等·标准】(即,行为一致的Eq trait, Ord traitHash trait实现)。
    • 所有权·实例
    • 引用
    • 智能指针

于是,若有<K, V> where K: Borrow<Q> + Eq + Hash, Q: Eq + Hash(其中,K: Borrow<Q>被读作:K被借入作为Q),那么由HashMap::get(_: &Q)检索出来的【值】就是由对应的HashMap::insert(_: K, _: V)添加的【值】。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-07-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Rust语言学习交流 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 【原创】从·类型转换·视角,浅谈Deref<Target = T>, AsRef<T>, Borrow<T>和From<T> trait差异
    • 概述
      • 如何给【自定义·类型】实现这些trait?
        • 如何触发这些trait引导的【类型转换】?
          • 这些trait的常见使用场景
            • 场景一
            • 场景二
        相关产品与服务
        容器服务
        腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档