rust中的指针大致可以分成三种:引用、裸指针和智能指针。
智能指针实际上是一种结构体,只不过它的行为类似指针。智能指针是对指针的一层封装,提供了一些额外的功能,比如自动释放内存。智能指针区别于常规结构体的特性在于,它实现了Deref和Drop这两个trait。Deref提供了解引用能力,Drop提供了自动析构的能力,正是之后这两个trait让智能指针有了类似指针的行为,而且比一般的指针更为强大,顾称之为:智能指针。
最简单直接的智能指针是box,其类型是Box<T>。box 允许你将一个值放在堆上而不是栈上。留在栈上的则是指向堆数据的指针。
Box<T>的应用场景一、使用Box<T>在堆上存储数据
如下示例:
这里定义了变量b,其值是存储在堆上的值为5的Box。在这个例子中,我们可以像数据是储存在栈上的那样访问 box 中的数据。根据所有权机制,当b这样的Box类型离开作用域时,它将被释放。这个释放过程作用于 box 本身(位于栈上)和它所指向的数据(位于堆上)。
二、Box<T>的内部实现
我们自己创建一个MyBox,来实现Box的功能。
1、new方法
new方法2、Deref trait
指针类型,有解引用的用法,但是我们的MyBox智能指针还没有这个功能,使用解引用会通过不了编译:
解引用的trait需求因此,为了实现trait,需要提供trait所需的方法实现。Deref trait,由标准库提供,要求实现名为deref的方法,其借用self并返回一个内部数据的引用。以下就是定义于MyBox之上的Deref实现:
实现deref traittype Target = T;
语法定义了用于此 trait 的关联类型。关联类型是一个稍有不同的定义泛型参数的方式。此处不作过多拓展。
deref 方法体中写入了 &self.0 ,这样 deref 返回了我希望通过 * 运算符访问的值的引用。
这样我们就可以使用解引用符*了。
注意:没有 Deref trait 的话,编译器只会解引用 & 引用类型。 deref 方法向编译器提供了获取任何实现了 Deref trait 的类型的值,并且调用这个类型的 deref 方法来获取一个它知道如何解引用的 & 引用的能力。
如开始时的那个示例中的*y代码,Rust事实上在底层运行了如下的代码:
*(y.deref())
3、Drop trait
对于智能指针模式来说第二个重要的 trait 是 Drop ,其允许我们在值要离开作用域时执行一些代码。可以为任何类型提供 Drop trait 的实现,同时所指定的代码被用于释放类似于文件或网络连接的资源。
如下代码:
析构函数drop给CustomSmartPointer结构体实现了一个drop方法,这个就类似于面向对象语言中的析构函数,最后输出:
输出这两行输出刚好和d和c这两个结构体实例创建的顺序相反。同时也说明这两个实例在离开作用域之后确实是调用drop方法了。
但值得注意的是:
我们不能直接调用drop功能。因为drop trait的目的就是进行自动的释放处理逻辑。
如我们调用c.drop()手动释放实例c:
手动析构错误信息如下:
错误信息错误信息告诉我们,不能显示地去做析构。
但是可以用std::mem::drop来提前drop值。
如下代码,用的是drop(c)来清理实例c:
drop(c)可以看到运行后的顺序:
输出字符串顺序可以看出,c是被提前释放掉了,所以c里面的drop方法第一个被执行。
网友评论