【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进行一系列的调用,来把它转换为所需的参数类型。这个操作在编译时完成,没有额外的性能开销。

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

rust 复制代码
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

以下是增添的部分:

rust 复制代码
fn hello(name: &str) {  
    println!("Hello, {}", name);  
}

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

写主函数看看实际使用:

rust 复制代码
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,那么写法会是:

rust 复制代码
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. 引用与借用)。

相关推荐
闲人编程2 分钟前
Python第三方库IPFS-API使用详解:构建去中心化应用的完整指南
开发语言·python·去中心化·内存·寻址·存储·ipfs
小厂永远得不到的男人6 分钟前
基于 Spring Validation 实现全局参数校验异常处理
java·后端·架构
CTRA王大大1 小时前
【golang】制作linux环境+golang的Dockerfile | 如何下载golang镜像源
linux·开发语言·docker·golang
zhangfeng11332 小时前
以下是基于图论的归一化切割(Normalized Cut)图像分割工具的完整实现,结合Tkinter界面设计及Python代码示
开发语言·python·图论
还梦呦3 小时前
2025年09月计算机二级Java选择题每日一练——第五期
java·开发语言·计算机二级
鱼鱼说测试4 小时前
postman接口自动化测试
开发语言·lua
從南走到北4 小时前
JAVA国际版东郊到家同城按摩服务美容美发私教到店服务系统源码支持Android+IOS+H5
android·java·开发语言·ios·微信·微信小程序·小程序
_不会dp不改名_4 小时前
C++ 20: Concepts 与Requires
开发语言·c++20
毅航4 小时前
从原理到实践,讲透 MyBatis 内部池化思想的核心逻辑
后端·面试·mybatis
展信佳_daydayup4 小时前
02 基础篇-OpenHarmony 的编译工具
后端·面试·编译器