スマートポインタ

ポインタは、メモリのアドレスを含む変数の一般的な概念です。このアドレスは、何らかの他のデータを参照、または「指します」。 Rustにおいて最もありふれた種類のポインタは参照です。参照については第4章で習いましたね。参照は&記号で示唆され、指している値を借用します。 データを参照すること以外に特別な能力は何もなく、オーバーヘッドもありません。

一方、スマートポインタは、ポインタのように振る舞いますが、追加のメタデータと能力があるデータ構造です。 スマートポインタという概念は、Rustに特有のものではありません。スマートポインタは、C++に端を発し、 他の言語にも存在しています。Rustには、参照以上の機能を提供する色々なスマートポインタが標準ライブラリに定義されています。 一般的な概念を探索するために、いくつかのスマートポインタの例を見ていきますが、その一つが参照カウント方式のスマートポインタ型です。 このポインタのおかげでデータに複数の所有者を持たせることができます。 所有者の数を追いかけ、所有者がいなくなったらデータの片付けをしてくれるからです。

所有権と借用の概念を持つRustでは、参照とスマートポインタにはもう1つ違いがあります: 参照はデータを借用するだけである一方で、スマートポインタは、多くの場合、指しているデータを所有します。

そのときはそう呼ばなかったものの、私達はすでに、この本の中でいくつかのスマートポインタに遭遇してきました。 例えば第8章のStringVec<T>です。これらの型はどちらも、あるメモリを所有しそれを弄ることができるので、 スマートポインタと見なされます。また、メタデータや追加の能力、あるいは保証もあります。 例えばStringは、その許容量をメタデータとして保持し、データが常に有効なUTF-8であると保証する追加の能力を持ちます。

スマートポインタは普通、構造体を使用して実装されています。通常の構造体とは異なり、 スマートポインタがDerefDropトレイトを実装します。Derefトレイトにより、スマートポインタ構造体のインスタンスは、 参照のように振る舞うことができるので、参照あるいはスマートポインタのどちらとも動作するようにコードを書くことができます。 Dropトレイトにより、スマートポインタのインスタンスがスコープを外れた時に走るコードをカスタマイズすることができます。 この章では、どちらのトレイトについても議論し、これらのトレイトがスマートポインタにとって重要な理由を説明します。

スマートポインタパターンがRustにおいてよく使われる一般的なデザインパターンであることを考えれば、この章で既存のスマートポインタを全て取り扱うことなどできません。 多くのライブラリに独自のスマートポインタがあり、自分だけのスマートポインタを書くことさえできるのです。 ここでは標準ライブラリの最もありふれたスマートポインタを取り扱っていきます。

  • ヒープに値を確保するBox<T>
  • 複数の所有権を可能にする参照カウント型のRc<T>
  • RefCell<T>を通してアクセスされ、コンパイル時ではなく実行時に借用規則を強制する型のRef<T>RefMut<T>

さらに、内部可変性パターンも扱います。そこでは不変な型が、内部の値を変更するためのAPIを公開するのです。 また、循環参照についても議論します。つまり、循環参照によっていかにしてメモリがリークするのか、そしてどうやってそれを回避するのかを議論します。

さあ、飛び込みましょう!