当前位置: 首页 > article >正文

【Rust自学】15.3. Deref trait Pt.2:隐式解引用转化与可变性

喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)
请添加图片描述

15.3.1. 函数和方法的隐式解引用转化(Deref Coercion)

隐式解引用转化(Deref Coercion)是为函数和方法提供的一种便捷特性。

它的原理是:*假如类型T实现了Deref trait,那么Deref Coercion可以把T的引用转化为T经过Deref操作后生成的引用。

当某类型的引用传递给函数或者是方法时,但它的类型与定义的参数类型不匹配,Deref Coercion就会自动发生。编译器会对deref进行一系列的调用,来把它转换为所需的参数类型。这个操作在编译时完成,没有额外的性能开销。

这句话比较绕,看个例子就明白了。我们接着上篇文章的代码来写:

use std::ops::Deref;  
  
struct MyBox<T>(T);  
  
impl<T> MyBox<T> {  
    fn new(x: T) -> MyBox<T> {  
        MyBox(x)  
    }  
}  
  
impl<T> Deref for MyBox<T> {  
    type Target = T;  
    fn deref(&self) -> &T {  
        &self.0  
    }  
}

这是上篇文章的代码,定义了MyBox元组结构体(元组结构体的介绍详见 5.1. 定义并实例化struct),创建了new函数,并为其实现了Deref trait,所以就可以使用一般的解引用操作来处理MyBox

以下是增添的部分:

fn hello(name: &str) {  
    println!("Hello, {}", name);  
}

hello这个函数接收&str,也就是字符串切片类型,然后打印出来。

写主函数看看实际使用:

fn main(){  
    let m = MyBox::new(String::from("Rust"));  
    hello(&m);  
}

mMyBox<String>类型,&m就是&MyBox<String>,而hello函数接收的是&str,但这么写并不会报错,这是为什么呢?

首先MyBox已经实现了Deref trait,所以Rust可以调用deref方法来把&MyBox<String>转化为&String,这就是刚才讲的那个比较绕的规则。

到这一步还没完,&String类型与&str类型不同,又是怎么转换的呢?因为String类型也实现了Deref trait,而且它的deref实现是返回一个字符串切片&str类型,所以Rust会在&String上使用deref&String转化为&str。最终这个类型就匹配了。

而如果Rust没有Deref Coercion,那么写法会是:

hello(&(*m)[..]);
  • 先使用解引用符号*mMyBox<String>转化为String
  • 加上引用符号&mString转化为&String
  • 通过切片操作 [..],可以获得 String 中的完整内容的引用,并且把其值从&String转化为&str

15.3.2. 解引用于可变性

可以使用DerefMut trait重载可变引用的*运算符。DerefMut相比Deref多了Mut,这是指DerefMut返回的是可变引用&mut T,而Deref返回的是不可变引用&T

在类型和trait满足下列三种情况时,Rust会执行Deref Coercion:

  • T:Deref<Target=U>,允许&T转换为&U
    T实现了Deref trait,而Deref trait下的deref方法的返回类型是&U,那么&T就可以被转化为&U
    举个例子,上文代码例的MyBox类型就实现了Deref trait,其deref方法的返回值是泛型参数&T,所以&MyBox就可以转换为&T

  • T:DerefMut<Target=U>,允许&mut T转换为&mut U
    T实现了DerefMut trait(DerefMut返回的是可变引用&mut T),而DerefMut trait下的deref方法的返回类型是&mut U,那么&mut T就可以被转化为&mut U

  • T:Deref<Target=U>,允许&mut T转化为&U
    Rust可以自动地把一个可变引用转化为不可变引用,但是反过来绝对不行。因为将不可变的引用转化为可变的引用要求引用是唯一的(借用规则中有讲,详见 4.4. 引用与借用)。


http://www.kler.cn/a/519947.html

相关文章:

  • 如何建设一个企业级的数据湖
  • 【学术会议-第五届机械设计与仿真国际学术会议(MDS 2025) 】前端开发:技术与艺术的完美融合
  • 【QT】 控件 -- 显示类
  • C# 类(Class)
  • 高速光模块中的并行光学和WDM波分光学技术
  • Kafka 深入服务端 — 时间轮
  • 【Leetcode】--- 接雨水
  • 分布式机器学习中【拓扑】与【通信】的区别和联系
  • CodeForces 611:New Year and Domino ← 二维前缀和
  • 单链表OJ篇
  • docker日志保留策略设置
  • Avalonia系列文章之再试牛刀
  • 【数据结构】时间复杂度空间复杂度
  • 用python实现接口下单
  • 用Ollama跑DeepSeek R1
  • 【Eigen教程】矩阵、数组和向量类(二)
  • P3978 [TJOI2015] 概率论
  • 利用metaGPT多智能体框架实现智能体-2
  • MarsCode青训营打卡Day10(2025年1月23日)|稀土掘金-147.寻找独一无二的糖葫芦串、119.游戏队友搜索
  • 什么是 Token,Token 的作用是什么?
  • 突破与重塑:逃离Java舒适区,借Go语言复刻Redis的自我突破和成长
  • flutter-android混合编译,原生接入
  • 在 JavaScript 中调用 OpenAI 的接口初识
  • 3-scala的类
  • 自定义数据集使用框架的线性回归方法对其进行拟合
  • 第30章 测试驱动开发中的设计模式解析(Python 版)