【Rust】——通过Deref trait将智能指针当作常规引用处理

这篇具有很好参考价值的文章主要介绍了【Rust】——通过Deref trait将智能指针当作常规引用处理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

💻博主现有专栏:

                C51单片机(STC89C516),c语言,c++,离散数学,算法设计与分析,数据结构,Python,Java基础,MySQL,linux,基于HTML5的网页设计及应用,Rust(官方文档重点总结),jQuery,前端vue.js,Javaweb开发,Python机器学习等
🥏主页链接:

                Y小夜-CSDN博客

目录

🎯追踪指针的值

🎯像引用一样使用Box

🎯自定义智能指针

🎯通过实现Deref trait 将某一类型像引用一样处理

🎯函数和方法的隐式Deref强制转换

🎯Deref强制转换如何与可变交互


        实现 Deref trait 允许我们重载 解引用运算符dereference operator*(不要与乘法运算符或通配符相混淆)。通过这种方式实现 Deref trait 的智能指针可以被当作常规引用来对待,可以编写操作引用的代码并用于智能指针。

        实现 Deref trait 允许我们重载 解引用运算符dereference operator*(不要与乘法运算符或通配符相混淆)。通过这种方式实现 Deref trait 的智能指针可以被当作常规引用来对待,可以编写操作引用的代码并用于智能指针。

🎯追踪指针的值

        常规引用是一个指针类型,一种理解指针的方式是将其看成指向储存在其他某处值的箭头。在示例 15-6 中,创建了一个 i32 值的引用,接着使用解引用运算符来跟踪所引用的值:

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

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

        变量 x 存放了一个 i32 值 5y 等于 x 的一个引用。可以断言 x 等于 5。然而,如果希望对 y 的值做出断言,必须使用 *y 来追踪引用所指向的值(也就是 解引用),这样编译器就可以比较实际的值了。一旦解引用了 y,就可以访问 y 所指向的整型值并可以与 5 做比较。

🎯像引用一样使用Box<T>

fn main() {
    let x = 5;
    let y = Box::new(x);

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

        将 y 设置为一个指向 x 值拷贝的 Box<T> 实例,而不是指向 x 值的引用。在最后的断言中,可以使用解引用运算符以 y 为引用时相同的方式追踪 Box<T> 的指针。接下来让我们通过实现自己的类型来探索 Box<T> 能这么做有何特殊之处。

🎯自定义智能指针

        为了体会默认情况下智能指针与引用的不同,让我们创建一个类似于标准库提供的 Box<T> 类型的智能指针。接着学习如何增加使用解引用运算符的功能。

        从根本上说,Box<T> 被定义为包含一个元素的元组结构体

struct MyBox<T>(T);

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

        这里定义了一个结构体 MyBox 并声明了一个泛型参数 T,因为我们希望其可以存放任何类型的值。MyBox 是一个包含 T 类型元素的元组结构体。MyBox::new 函数获取一个 T 类型的参数并返回一个存放传入值的 MyBox 实例。

fn main() {
    let x = 5;
    let y = MyBox::new(x);

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

得到的编译错误是:

$ cargo run
   Compiling deref-example v0.1.0 (file:///projects/deref-example)
error[E0614]: type `MyBox<{integer}>` cannot be dereferenced
  --> src/main.rs:14:19
   |
14 |     assert_eq!(5, *y);
   |                   ^^

For more information about this error, try `rustc --explain E0614`.
error: could not compile `deref-example` due to previous error

   MyBox<T> 类型不能解引用,因为我们尚未在该类型实现这个功能。为了启用 * 运算符的解引用功能,需要实现 Deref trait。

🎯通过实现Deref trait 将某一类型像引用一样处理

        为了实现 trait,需要提供 trait 所需的方法实现。Deref trait,由标准库提供,要求实现名为 deref 的方法,其借用 self 并返回一个内部数据的引用。示例 15-10 包含定义于 MyBox 之上的 Deref 实现:

use std::ops::Deref;

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

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

type Target = T; 语法定义了用于此 trait 的关联类型。

        没有 Deref trait 的话,编译器只会解引用 & 引用类型。deref 方法向编译器提供了获取任何实现了 Deref trait 的类型的值,并且调用这个类型的 deref 方法来获取一个它知道如何解引用的 & 引用的能力。

*(y.deref())

        Rust 将 * 运算符替换为先调用 deref 方法再进行普通解引用的操作,如此我们便不用担心是否还需手动调用 deref 方法了。Rust 的这个特性可以让我们写出行为一致的代码,无论是面对的是常规引用还是实现了 Deref 的类型。

   deref 方法返回值的引用,以及 *(y.deref()) 括号外边的普通解引用仍为必须的原因在于所有权。如果 deref 方法直接返回值而不是值的引用,其值(的所有权)将被移出 self。在这里以及大部分使用解引用运算符的情况下我们并不希望获取 MyBox<T> 内部值的所有权。

        注意,每次当我们在代码中使用 * 时, * 运算符都被替换成了先调用 deref 方法再接着使用 * 解引用的操作,且只会发生一次,不会对 * 操作符无限递归替换,解引用出上面 i32 类型的值就停止了,这个值与示例 15-9 中 assert_eq! 的 5 相匹配。

🎯函数和方法的隐式Deref强制转换

        Deref 强制转换deref coercions)将实现了 Deref trait 的类型的引用转换为另一种类型的引用。例如,Deref 强制转换可以将 &String 转换为 &str,因为 String 实现了 Deref trait 因此可以返回 &str。Deref 强制转换是 Rust 在函数或方法传参上的一种便利操作,并且只能作用于实现了 Deref trait 的类型。当这种特定类型的引用作为实参传递给和形参类型不同的函数或方法时将自动进行。这时会有一系列的 deref 方法被调用,把我们提供的类型转换成了参数所需的类型。

        Deref 强制转换的加入使得 Rust 程序员编写函数和方法调用时无需增加过多显式使用 & 和 * 的引用和解引用。这个功能也使得我们可以编写更多同时作用于引用或智能指针的代码。

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

        当所涉及到的类型定义了 Deref trait,Rust 会分析这些类型并使用任意多次 Deref::deref 调用以获得匹配参数的类型。这些解析都发生在编译时,所以利用 Deref 强制转换并没有运行时损耗!

🎯Deref强制转换如何与可变交互

        类似于如何使用 Deref trait 重载不可变引用的 * 运算符,Rust 提供了 DerefMut trait 用于重载可变引用的 * 运算符。

  • 当 T: Deref<Target=U> 时从 &T 到 &U
  • 当 T: DerefMut<Target=U> 时从 &mut T 到 &mut U
  • 当 T: Deref<Target=U> 时从 &mut T 到 &U

        头两个情况除了第二种实现了可变性之外是相同的:第一种情况表明如果有一个 &T,而 T 实现了返回 U 类型的 Deref,则可以直接得到 &U。第二种情况表明对于可变引用也有着相同的行为。

        第三个情况有些微妙:Rust 也会将可变引用强转为不可变引用。但是反之是 不可能 的:不可变引用永远也不能强转为可变引用。因为根据借用规则,如果有一个可变引用,其必须是这些数据的唯一引用(否则程序将无法编译)。将一个可变引用转换为不可变引用永远也不会打破借用规则。将不可变引用转换为可变引用则需要初始的不可变引用是数据唯一的不可变引用,而借用规则无法保证这一点。因此,Rust 无法假设将不可变引用转换为可变引用是可能的。文章来源地址https://www.toymoban.com/news/detail-859269.html

到了这里,关于【Rust】——通过Deref trait将智能指针当作常规引用处理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言指针操作(七)通过指针引用字符串

    通过指针引用字符串详解,以及字符指针变量和字符数组的比较、 在平常的案例中已大量地使用了字符串,如在 printf函数中输出一个字符串。这些字符串都是以直接形式 (字面形式) 给出的,在一对双引号中包含若干个合法的字符。在本节中将介绍使用字符串的更加灵活方便

    2024年02月03日
    浏览(52)
  • 8.3 【C语言】通过指针引用数组

    所谓数组元素的指针就是数组元素的地址。 可以用一个指针变量指向一个数组元素。例如: int a[10]={1,3,5,7,9,11,13,15,17,19}; int *p; p=a[0]; 引用数组元素可以用下标法,也可以用指针法,即通过指向数组元素的指针找到所需的元素。 在指针已指向一个数组元素时,可以对指针进

    2024年02月12日
    浏览(45)
  • 8.4 【C语言】通过指针引用字符串

    在C程序中,字符串是存放在字符数组中的。想引用一个字符串,可以用以下两种方法。 (1)用字符数组存放一个字符串,可以通过数组名和下标引用字符串中一个字符,也可以通过数组名和格式声明“%s”输出该字符串。 例:定义一个字符数组,在其中存放字符串“I love

    2024年02月11日
    浏览(35)
  • 【Rust 基础篇】Rust Box 智能指针

    在 Rust 中, Box 是一种智能指针类型,用于在堆上分配内存并管理其生命周期。 Box 提供了堆分配的功能,并在所有权转移时负责释放内存。本篇博客将详细介绍 Rust 中 Box 智能指针的使用方法和相关概念。 Box 是一个指向堆上分配的值的指针。它提供了所有权转移和释放内存

    2024年02月16日
    浏览(41)
  • C++智能指针学习——小谈引用计数

    目录 前言 控制块简介 共享控制块 引用计数与弱引用计数创建过程 __shared_ptr __shared_count _Sp_counted_base 弱引用计数增加过程 再谈共享控制块 __weak_count 引用计数增加过程 弱引用计数的减少过程 弱引用计数减为0 引用计数的减少过程 引用计数减为0 参考文章 本文结合源码讨论

    2024年04月08日
    浏览(49)
  • Rust- 智能指针

    A smart pointer is a data structure that not only acts like a pointer but provides additional functionality. This “smartness” comes from the fact that smart pointers encapsulate additional logical or semantic rules, which are automatically applied to simplify memory or resource management tasks. While different programming languages implement smart point

    2024年02月14日
    浏览(45)
  • rust学习-智能指针

    示例1 无意义的例子:将一个单独的值存放在堆上并不是很有意义,b更应该放到栈上 示例2-递归类型 一种无法在编译时知道大小的类型是 递归类型(recursive type) 其值的一部分可以是相同类型的另一个值 递归类型来源于Lisp语言:cons 函数(“construct function\\\" 的缩写)利用两

    2024年02月16日
    浏览(38)
  • rust 智能指针

    Rust中基本数据类型(如整数、浮点数、布尔值等)通常存储在栈上。而动态分配的数据,如 BoxT 和 VecT 等,存储在堆上。 Rust 中 Box 是一种智能指针类型,通常用于将值放置在堆上而不是栈上。在 Rust 中,由于所有值的默认生命周期都在当前作用域结束时结束,因此在情况需

    2024年02月06日
    浏览(90)
  • 【Rust】Rust学习 第十四章智能指针

    指针  ( pointer )是一个包含内存地址的变量的通用概念。这个地址引用,或 “指向”(points at)一些其他数据。Rust 中最常见的指针是第四章介绍的  引用 ( reference )。引用以   符号为标志并借用了他们所指向的值。除了引用数据没有任何其他特殊功能。它们也没有任

    2024年02月12日
    浏览(42)
  • 【Rust】Rust学习 第十五章智能指针

    指针  ( pointer )是一个包含内存地址的变量的通用概念。这个地址引用,或 “指向”(points at)一些其他数据。Rust 中最常见的指针是第四章介绍的  引用 ( reference )。引用以   符号为标志并借用了他们所指向的值。除了引用数据没有任何其他特殊功能。它们也没有任

    2024年02月12日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包