zoukankan      html  css  js  c++  java
  • Rust-智能指针:通过Deref trait 将智能指针当作常规引用处理

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

    通过解引用运算符追踪指针的值

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

        let x = 5;
        let y = &x;
        assert_eq!(5,x);
        assert_eq!(5,*y);

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

    相反如果尝试编写 assert_eq!(5,y),则会得到如下编译错误:

    error[E0277]: can't compare `{integer}` with `&{integer}`
      --> src/main.rs:31:5
       |
    31 |     assert_eq!(5,y);
       |     ^^^^^^^^^^^^^^^^ no implementation for `{integer} == &{integer}`
       |
       = help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}`
       = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)

    不允许比较数字的引用与数字,因为它们是不同的类型。必须使用解引用运算符追踪引用所指向的值。

    像引用一样使用Box<T>

    可以使用Box<T>代替引用来重写以上的示例代码,解引用运算符也一样能工作,如下所示:

        let x = 5;
        let y = Box::new(x);
        assert_eq!(5,x);
        assert_eq!(5,*y);

    在Box<i32>上使用解引用运算符。

    自定义智能指针

    为了体会默认情况下智能指针与引用的不同,让我们创建一个类似于标准库提供的Box<T>类型的智能指针。

    从根本上说,Box<T>被定义为包含一个元素的元组结构体,所以在以下的一个示例中以相同的方式定义了MyBox<T>类型。我们还定义了new函数来对应定义于Box<T>的new函数:

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

    这里定义了一个结构体MyBox并声明了一个泛型参数T,因为我们希望其可以存放任何类型的值。MyBox是一个包含T类型元素的元组结构体。

    MyBox::new函数获取一个T类型的参数并返回一个存放传入值的MyBox实例。我们修改下之前的代码,使用MyBox<T>类型代替Box<T>,示例代码不能编译,因为Rust不知道如何解引用MyBox:

        let x = 5;
        let y = MyBox::new(x);
        assert_eq!(5, x);
        assert_eq!(5, *y);

    得到的编译错误是:

    error[E0614]: type `MyBox<{integer}>` cannot be dereferenced
      --> src/main.rs:32:19
       |
    32 |     assert_eq!(5, *y);
       |                   ^^

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

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

    为了实现trait,需要提供trait所需的方法实现。Deref trait,由标准库提供,要求实现名为deref的方法,其借用self并返回一个内部数据的引用。MyBox<T>上的Deref实现:

    impl<T> Deref for MyBox<T> {
        type Target = T;
    
        fn deref(&self) -> &T {
            &self.0
        }
    }

    type Targe = T; 语法定义了用于此trait的关联类型。关联类型是一个稍有不同的定义泛型参数的方式。

    deref方法体中写入了 &self.0, 这样deref返回了我希望通过 * 运算符访问的值的引用。

    深入学习

  • 相关阅读:
    通过加载Xib文件来创建UITableViewCell造成复用数据混乱问题方案
    iOS开发过程中常见错误问题及解决方案
    iOS开发常用第三方库
    KVC和KVO的理解(底层实现原理)
    iOS面试必备-iOS基础知识
    iOS应用适配IPV6
    Runtime运行时的那点事儿
    iOS应用性能调优的25个建议和技巧
    iOS清除缓存功能开发
    微信浏览器跳转页面后再返回,如何恢复到跳转前的位置的问题。
  • 原文地址:https://www.cnblogs.com/johnnyzhao/p/15350811.html
Copyright © 2011-2022 走看看