スマートポインタ

ポインタは、メモリのアドレスを含む変数の一般的な概念です。このアドレスは、何らかの他のデータを参照、または「指します」。 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を公開するのです。 また、循環参照についても議論します。つまり、循環参照によっていかにしてメモリがリークするのか、そしてどうやってそれを回避するのかを議論します。

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