【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. 引用与借用)。

相关推荐
qq_447663051 小时前
java-----多线程
java·开发语言
a辰龙a1 小时前
【Java报错解决】警告: 源发行版 11 需要目标发行版 11
java·开发语言
听海边涛声1 小时前
JDK长期支持版本(LTS)
java·开发语言
IpdataCloud1 小时前
Java 获取本机 IP 地址的方法
java·开发语言·tcp/ip
MyMyMing1 小时前
Java的输入和输出
java·开发语言
Easonmax1 小时前
【javaSE】内部类(来自类和对象的补充)
开发语言·javascript·ecmascript
云夏之末1 小时前
【Java报错已解决】java.lang.UnsatisfiedLinkError
java·开发语言
eybk2 小时前
Qpython+Flask监控添加发送语音中文信息功能
后端·python·flask
计算机-秋大田2 小时前
基于SpringBoot的假期周边游平台的设计与实现(源码+SQL脚本+LW+部署讲解等)
java·vue.js·spring boot·后端·课程设计
li星野2 小时前
QT:图像上绘制图形
开发语言·qt