我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Rust 中 Deref Coercion讲解

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Rust 中 Deref Coercion讲解

0x00 前言

写这个文档的初衷是因为在中文社区看到一个非常不负责任的翻译,将 “implicit deref coercion” 翻译成 “隐式 deref 强制”,于是觉得有必要记录一下,以防止后来的新手在这里翻车。
首先需要解释一下 “coercion” 在编程语言文档中尤其是涉及到类型转换时的中文意思。
类型转换 (type conversion) 包括显式指定被转换到的类型的显式转换 (explicit conversion) 或称 cast,以及与之相对的隐式转换 (implicit conversion) 或称 coercion。因为翻译不准等原因,这两者之间经常被混淆。
cast 和 coercion 同时出现的时候,中文把前者翻译成 “显式类型转换”,后者翻译成 “隐式类型转换”。

Rust 的设计理念一向是显式比隐式好,也就是说所有的行为尽量在代码中表现出来。但也是有例外的,例如接下来我们要讨论的两个话题。

0x01 Deref Trait

Rust 中有一对运算符 &*,分别表示对一个变量的引用和解引用。
例如下面的代码:

fn main() {
    let x = 5;
    let y = &x;

    assert_eq!(5, x);
    assert_eq!(5, *y);
}

如果按照 C 语言的思维方式,这两个操作符是互补的,即互为逆操作,但在 Rust 中并不适用。当一个类型实现了 Deref 这个 Trait 后,对该类型显式执行 *y 操作时,Rust 将隐式执行 *(y.deref())
如果没有实现 Deref trait,只有引用类型可以被解引用,而实现了 Deref trait 后,编译器将隐式执行 deref 决定返回怎样的引用类型。

Deref Trait 的定义如下:

pub trait Deref {
    type Target: ?Sized;

    fn deref(&self) -> &Self::Target;
}

有一个很有趣的点,虽然是 Deref 操作,但是返回类型却是一个引用类型。这个在官方文档中给出了解释:

The reason the deref method returns a reference to a value, and that the plain dereference outside the parentheses in *(y.deref()) is still necessary, is to do with the ownership system. If the deref method returned the value directly instead of a reference to the value, the value would be moved out of self. We don’t want to take ownership of the inner value inside MyBox in this case or in most cases where we use the dereference operator.

主要原因是为了与大多数场景下的 ownership 机制适配。

通过了解 Rust 的 Deref Trait 后,我们可以得出结论:在 Rust 中 *&T&*T 不一定是同一个类型,例如下面示例:

use std::ops::Deref;

#[derive(Copy, Clone, Debug)]
struct MyBox {
    alpha: i32,
}

impl Deref for MyBox {
    type Target = i32;

    fn deref(&self) -> &Self::Target {
        &self.alpha
    }
}

fn main() {
    let beta = MyBox { alpha: 32 };
    let gamma = &*beta; // &i32
    let delta = *β // Mybox
    println!("{:?}, {:?}", gamma, delta);
}

0x02 Implicit Deref Coercion

Deref coercion converts a reference to a type that implements the Deref trait into a reference to another type.

最初接触到 Deref coercion 的场景通常是使用 &str 作为参数的函数,传入 &String 是可以编译通过的,习惯了 Rust 大爷苛刻的编译器后觉得这不可思议,深入了解后才知道,Rust 内部实现了 String 类型的 Deref trait,并且 type Target = &str
当引用作为函数或方法的参数时,Rust 编译器将隐式执行 deref coercion,以找到适配的类型。这样省去了 *& 的繁琐操作,但讲真对新手确实不友好。下面是一个示例:

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

struct MyBox<T>(T);

impl<T> MyBox<T> {
    fn new(x: T) -> MyBox<T> {
        MyBox(x)
    }
}

use std::ops::Deref;

impl<T> Deref for MyBox<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

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

再看一个有意思的示例:

fn main() {
    let s = "Hello, Rust!";
    println!("length: {}", s.len());
    println!("length: {}", (&s).len());
    println!("length: {}", (&&&&&&&&&&&&&s).len());
}

上面的示例是可以编译通过的,我们如果使用 &&&&&&&&&&str 类型来调用成员方法,也是可以的。原因是 Rust 编译器的 deref coercion 是递归的,当它找不到这个成员方法的时候会自动尝试使用 deref() 方法后再找该方法,一直递归下去。编译器在&&&str 类型里面找不到 len 方法,就尝试将它 deref(),变成 &&str 类型,再寻找 len 方法,还是没找到,那么继续 deref(),变成 &str,现在找到 len 方法了,于是就调用这个方法。

0x03 Option 中的 as_deref()

熟练的使用 Option 可以在 Rust 开发中节省很多头发。当需要将 Option<T> 转化为 Option<&T> 时,我们通常使用 Option.as_ref() 操作,再结合 map() 方法可以在不转移所有权的情况下使用 Option 中的变量。当看到 Option.as_deref() 操作时,我们首先会望文生义的认为是将 Option<&T> 转化为 Option<T>,但理解了前两节的内容后会懂得 Option.as_deref() 的操作其实是 Option.as_ref().map(|s| s.deref()) 的简写形式,返回的仍然是一个引用,目的是为了使用 Rust 中的 deref coercion 机制。

参考文档

https://doc.rust-lang.org/std/ops/trait.Deref.html
https://doc.rust-lang.org/book/ch15-02-deref.html
https://stackoverflow.com/questions/8857763/what-is-the-difference-between-casting-and-coercing
https://mp.weixin.qq.com/s/G28XE1rfX0nT6zIi86ji0Q
https://blog.csdn.net/weixin_39702559/article/details/112276392
https://blog.csdn.net/JAN6055/article/details/125774473

到此这篇关于Rust 中 Deref Coercion 介绍的文章就介绍到这了,更多相关Rust  Deref Coercion内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Rust 中 Deref Coercion讲解

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Rust 中 Deref Coercion讲解

Rust的设计理念一向是显式比隐式好,也就是说所有的行为尽量在代码中表现出来,这篇文章主要介绍了Rust 中 Deref Coercion 介绍,需要的朋友可以参考下
2022-11-13

rust异步编程详细讲解

这篇文章主要介绍了rust异步编程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
2022-12-16

Rust包和Crate超详细讲解

这篇文章主要介绍了Rust包管理和Crate,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
2022-12-16

RUST异步流处理方法详细讲解

这篇文章主要介绍了RUST异步流处理方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
2022-12-16

Rust裸指针的安全性实例讲解

裸指针是一个不包含所有权和借用关系的原始指针,它们与常规指针相比没有任何限制和保护措施,这篇文章主要介绍了Rust裸指针的安全性实例,需要的朋友可以参考下
2023-05-20

2022最新Rust变量与数据类型讲解

rust是强类型语言所有变量、常量都必须有明确的数据类型,这篇文章主要介绍了Rust变量与数据类型,需要的朋友可以参考下
2022-11-13

Rust结构体的定义与实例化详细讲解

结构体是一种自定义的数据类型,它允许我们将多个不同的类型组合成一个整体。下面我们就来学习如何定义和使用结构体,并对比元组与结构体之间的异同,需要的可以参考一下
2022-12-12

详解Rust中的方法

方法其实就是结构体的成员函数,在C语言中的结构体是没有成员函数的,但是Rust毕竟也是一门面向对象的编程语言,所以给结构体加上方法的特性很符合面向对象的特点,这篇文章主要介绍了Rust中的方法,需要的朋友可以参考下
2022-11-13

Rust中Cargo的使用详解

Cargo是Rust的构建系统和包管理器,⼤多数Rustacean们使⽤Cargo来管理他们的Rust项⽬,因为它可以为你处理很多任务,⽐如构建代码、下载依赖库并编译这些库,这篇文章主要介绍了Rust中Cargo的使用,需要的朋友可以参考下
2022-11-16

Rust中的函数指针详解

Rust是一种现代的系统编程语言,它支持函数指针。函数指针是指向函数的指针,可以将函数作为参数传递给其他函数或存储在变量中。Rust中的函数指针可以用于实现回调函数、动态分发和多态等功能。本文将介绍Rust中的函数指针的基本用法和高级用法。
2023-05-18

Rust之Substrate框架中Core详解

Substrate是一个用于构建区块链的开发框架,它由Parity团队基于Rust语言开发而成,是一个开箱即用的区块链构造器,本文详细介绍了Substrate框架中的Core,需要的朋友可以参考下
2023-05-18

详解Rust中的所有权机制

Rust 语言提供了跟其他系统编程语言相同的方式来控制你使用的内存,但拥有数据所有者在离开作用域后自动清除其数据的功能意味着你无须额外编写和调试相关的控制代码,这篇文章主要介绍了Rust中的所有权机制,需要的朋友可以参考下
2022-11-13

Rust中的derive属性示例详解

derive属性的出现解决了手动实现一些特性时需要编写大量重复代码的问题,它可以让编译器自动生成这些特性的基本实现,从而减少了程序员需要编写的代码量,这篇文章主要介绍了Rust中的derive属性详解,需要的朋友可以参考下
2023-05-16

Rust中的不安全代码详解

这篇文章主要为大家介绍了Rust中的不安全代码详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-05-18

Rust之Substrate框架中的pallet详解

Pallet是Substrate区块链的基础模块,它定义了区块链的业务逻辑和状态转换规则。开发人员可以使用现有的Pallet来快速构建区块链,也可以开发自定义的Pallet来实现特定的功能,感兴趣的小伙伴可以参考阅读下
2023-05-18

详解Rust中的变量与常量

大多数尝试过Rust的人都希望继续使用它。但是如果你没有使用过它,你可能会想——什么是Rust,如何理解Rust中的变量与常量,感兴趣的朋友跟随小编一起看看吧
2022-11-13

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录