スマートポインタ
ポインタは、メモリのアドレスを含む変数の一般的な概念です。このアドレスは、何らかの他のデータを参照、または「指します」。
Rustにおいて最もありふれた種類のポインタは参照です。参照については第4章で習いましたね。参照は&
記号で示唆され、指している値を借用します。データを参照すること以外に特別な能力は何もありません。
また、オーバーヘッドもなく、ポインタの中では最も頻繁に使われます。
一方、スマートポインタは、ポインタのように振る舞うだけでなく、追加のメタデータと能力があるデータ構造です。 スマートポインタという概念は、Rustに特有のものではありません。スマートポインタは、C++に端を発し、 他の言語にも存在しています。Rustでは、標準ライブラリに定義された色々なスマートポインタが、 参照以上の機能を提供します。この章で探究する一つの例が、参照カウント方式のスマートポインタ型です。 このポインタのおかげでデータに複数の所有者を持たせることができます。 所有者の数を追いかけ、所有者がいなくなったらデータの片付けをしてくれるからです。
所有権と借用の概念を使うRustにおいて、参照とスマートポインタにはもう1つ違いがあります。参照はデータを借用するだけのポインタなのです。 対照的に多くの場合、スマートポインタは指しているデータを所有します。
私達はすでに、この本の中でいくつかのスマートポインタに遭遇してきました。例えば第8章のString
やVec<T>
です。ただし、私達はそれらをスマートポインタとは呼んでいませんでした。
これらの型がどちらもスマートポインタに数えられるのは、あるメモリを所有しそれを弄ることができるからです。
また、メタデータ(キャパシティなど)や追加の能力、あるいは保証(String
ならデータが常に有効なUTF-8であると保証することなど)もあります。
スマートポインタは普通、構造体を使用して実装されています。スマートポインタを通常の構造体と区別する特徴は、
スマートポインタがDeref
とDrop
トレイトを実装していることです。Deref
トレイトにより、スマートポインタ構造体のインスタンスは、
参照のように振る舞うことができるので、参照あるいはスマートポインタのどちらとも動作するコードを書くことができます。
Drop
トレイトにより、スマートポインタのインスタンスがスコープを外れた時に走るコードをカスタマイズすることができます。
この章では、どちらのトレイトについても議論し、これらのトレイトがスマートポインタにとって重要な理由を説明します。
スマートポインタパターンがRustにおいてよく使われる一般的なデザインパターンであることを考えれば、この章で既存のスマートポインタを全て取り扱うことなどできません。 多くのライブラリに独自のスマートポインタがあり、自分だけのスマートポインタを書くことさえできるのです。 ここでは標準ライブラリの最もありふれたスマートポインタを取り扱っていきます。
- ヒープに値を確保する
Box<T>
- 複数の所有権を可能にする参照カウント型の
Rc<T>
RefCell<T>
を通してアクセスされ、コンパイル時ではなく実行時に借用規則を強制する型のRef<T>
とRefMut<T>
さらに、内部可変性パターンも扱います。そこでは不変な型が、内部の値を変更するためのAPIを公開するのです。 また、循環参照についても議論します。つまり、循環参照によっていかにしてメモリがリークするのか、そしてどうやってそれを回避するのかを議論します。
さあ、飛び込みましょう!