Rust - 智能指针



Rust 默认情况下将所有内容分配在栈上。您可以通过将它们包装在智能指针(如Box)中来将内容存储在堆上。像 Vec 和 String 这样的类型隐式地帮助堆分配。智能指针实现了下表中列出的特征。这些特征将智能指针与普通的结构体区分开来:

序号 特征名称 包 & 描述
1 Deref

std::ops::Deref

用于不可变的解引用操作,例如 *v。

2 Drop

std::ops::Drop

用于在值超出作用域时运行某些代码。这有时被称为析构函数

在本章中,我们将学习Box智能指针。我们还将学习如何创建像 Box 这样的自定义智能指针。

Box

Box 智能指针也称为盒,允许您将数据存储在堆上而不是栈上。栈包含指向堆数据的指针。除了将数据存储在堆上之外,Box 没有性能开销。

让我们看看如何使用盒将 i32 值存储在堆上。

fn main() {
   let var_i32 = 5; 
   //stack
   let b = Box::new(var_i32); 
   //heap
   println!("b = {}", b);
}

输出

b = 5

为了访问变量指向的值,请使用解引用。* 用作解引用运算符。让我们看看如何将解引用与 Box 一起使用。

fn main() {
   let x = 5; 
   //value type variable
   let y = Box::new(x); 
   //y points to a new value 5 in the heap

   println!("{}",5==x);
   println!("{}",5==*y); 
   //dereferencing y
}

变量 x 是一个值为 5 的值类型。因此,表达式5==x将返回 true。变量 y 指向堆。要访问堆中的值,我们需要使用*y进行解引用。*y返回 5。因此,表达式5==*y返回 true。

输出

true
true

图示 - Deref 特征

标准库提供的 Deref 特征要求我们实现一个名为deref的方法,该方法借用self并返回对内部数据的引用。以下示例创建了一个结构体MyBox,它是一个泛型类型。它实现了Deref特征。此特征帮助我们使用*y访问y包装的堆值。

use std::ops::Deref;
struct MyBox<T>(T);
impl<T> MyBox<T> { 
   // Generic structure with static method new
   fn new(x:T)-> MyBox<T> {
      MyBox(x)
   }
}
impl<T> Deref for MyBox<T> {
   type Target = T;
   fn deref(&self) -> &T {
      &self.0 //returns data
   }
}
fn main() {
   let x = 5;
   let y = MyBox::new(x); 
   // calling static method
   
   println!("5==x is {}",5==x);
   println!("5==*y is {}",5==*y); 
   // dereferencing y
   println!("x==*y is {}",x==*y);
   //dereferencing y
}

输出

5==x is true
5==*y is true
x==*y is true

图示 - Drop 特征

Drop 特征包含drop()方法。当实现此特征的结构体超出作用域时,将调用此方法。在某些语言中,程序员必须在每次完成使用智能指针实例后调用代码来释放内存或资源。在 Rust 中,您可以使用 Drop 特征实现自动内存释放。

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
   }
}
impl<T> Drop for MyBox<T>{
   fn drop(&mut self){
      println!("dropping MyBox object from memory ");
   }
}
fn main() {
   let x = 50;
   MyBox::new(x);
   MyBox::new("Hello");
}

在上面的示例中,drop 方法将被调用两次,因为我们在堆中创建了两个对象。

dropping MyBox object from memory
dropping MyBox object from memory
广告