本文へスキップ
BecomeCoder

Rustコース · 第10章 スマートポインタと並行性 · レッスン39

Box ― ヒープに置くいちばん素朴な箱

ブラウザで完結

導入

スマートポインタとは、「ただのポインタ」に追加の機能や保証を持たせた型のことです。実は第3章から使ってきた StringVec もスマートポインタの一種でした。その最も単純な形が Box<T>——「値をヒープに置く」ためのいちばん素朴な箱です。

説明

Box<T> は、値をヒープに確保し、そのポインタをスタックで持ちます。

fn main() {
    let b = Box::new(5);    // 5 をヒープに置き、b はそれを指す
    println!("b = {b}");     // 自動で中身が参照される → 5
}   // b がスコープを抜けると、ヒープの 5 も自動解放

5 のような小さな値をわざわざヒープに置く意味は普段ありませんが、Box が本当に必要になるのは 「サイズがコンパイル時に決まらない型」 を扱うときです。代表例が、自分自身を含む再帰的なデータ構造です。

// 連結リスト:各要素が「次の要素」を持つ
enum List {
    Cons(i32, Box<List>),   // 値と「次への Box」
    Nil,                     // 終端
}

use List::{Cons, Nil};

fn main() {
    // 1 -> 2 -> 3 -> 終端
    let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
}

もし Cons(i32, List)直接書くと、List の中に List が入り、その中にまた List……と、サイズが無限になってコンパイルできません。Box<List> にすると、中身はヒープに置かれ、構造体が持つのはサイズ固定のポインタだけになります。これで「入れ子の深さが実行時に決まる」構造をスタック上の固定サイズで表現できます。第3章の「可変サイズはヒープ+ポインタ」が、ここで効いてくるわけです。

graph LR
    subgraph stack["スタック"]
        b["b: Box(ptr ●)"]
    end
    subgraph heap["ヒープ"]
        v["値 5"]
    end
    b -->|指す| v

Box は所有権のルールにそのまま従います。Box を持つ変数がその中身のヒープデータの所有者で、スコープを抜ければ自動解放。「所有者は1人」も守られます。

試すには

Box::new(値) は「値をヒープへ」の最も基本の道具です。再帰的な型(リスト・木構造)を Rust で作るときにまず登場します。「なぜ直接ではダメで Box が要るのか」——サイズが確定しないから、という理由を押さえておきましょう。

実際に動かしてみよう

下のエディタにRustを書いて「実行」を押すと、学習用シミュレータが println! の出力を表示します(本物のrustcではなく、教材の範囲を再現した軽量エンジンです)。struct・enum・match・トレイト・Vec/String/HashMap・Option/Result なども動きます。本文の例を書き換えて動かしてみましょう(所有権・借用チェッカーのコンパイルエラーは再現しないため、動きの確認用として使ってください)。

Rust — ブラウザ内で実行(学習用シミュレータ)

Rustの教材サブセットを動かす学習用シミュレータを読み込みます(本物のrustcではなく、動きを再現した軽量な自作エンジンです)。
スクロールして表示された時点でも自動で読み込まれます。