さび-スマートポインタ

Rustは、デフォルトでスタック上のすべてを割り当てます。Boxのようなスマートポインタでそれらをラップすることにより、ヒープに物を格納することができます。VecやStringのようなタイプは、暗黙的にヒープの割り当てに役立ちます。スマートポインタは、以下の表にリストされている特性を実装します。スマートポインタのこれらの特性は、通常の構造体とは異なります。

シニア番号 特性名 パッケージと説明
1 Deref

std::ops::Deref

* vなどの不変の逆参照操作に使用されます。

2 落とす

std::ops::Drop

値がスコープ外になったときにコードを実行するために使用されます。これはデストラクタと呼ばれることもあります

この章では、 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という名前の1つのメソッドを実装する必要があります。このメソッドは、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()メソッドが含まれています。このメソッドは、この特性を実装した構造がスコープ外になったときに呼び出されます。一部の言語では、プログラマーは、スマートポインターのインスタンスの使用を終了するたびに、コードを呼び出してメモリまたはリソースを解放する必要があります。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");
}

上記の例では、ヒープ内に2つのオブジェクトを作成しているため、dropメソッドが2回呼び出されます。

dropping MyBox object from memory
dropping MyBox object from memory