例: 参照

// Copyright 2026 Google LLC
// SPDX-License-Identifier: Apache-2.0

fn main() {
    let mut boxed = Box::new(123);
    let a: *mut i32 = &mut *boxed as *mut i32;
    let b: *mut i32 = std::ptr::null_mut();

    println!("{:?}", *a);
    println!("{:?}", b.as_mut());
}

構文の理解を確認する

  • Box<i32> 型は、box が所有する、ヒープ上の整数への参照です。

  • *mut i32 型は、いわゆる整数への生ポインタであり、その所有権をコンパイラは 把握していません。プログラマーは、コンパイラの助けなしにルールが守られることを 保証する必要があります。

    • 注: 生ポインタは所有権の情報を Rust に提供しません。ポインタは、意味的には データを所有していることも、意味的には借用していることもありますが、その 情報はプログラマーの頭の中にしか存在しません。
  • &mut *boxed as *mut _ 式:

    • *boxed は …
    • &mut *boxed は …
    • 最後に、as *mut i32 はその参照をポインタにキャストします。
  • &mut i32 のような参照は、その参照先を「借用」します。これが Rust の 所有権システムです。

所有権の理解を確認する

  • コードを順に追う:

    • (3 行目) box をデリファレンスして 123 への生ポインタを作成し、新しい 参照を作って、その新しい参照をポインタとしてキャストします。
    • (4 行目) NULL 値を持つ生ポインタを作成します
    • (7 行目) .as_mut() で生ポインタを Option に変換します
  • Rust ではポインタが null を取り得ることを強調する(参照とは異なります)。

  • コンパイルしてエラーメッセージを確認する。

  • 議論する

    • (6 行目) println!("{:?}", *a);
      • 先頭の * は生ポインタをデリファレンスします。
      • これは明示的な操作です。一方、通常の参照では、Deref トレイトのおかげで ほとんどの場合は暗黙にデリファレンスされます。これは “auto-deref” と 呼ばれます。
      • 生ポインタのデリファレンスは unsafe な操作です。
      • unsafe ブロックが必要です。
    • (7 行目) println!("{:?}", b.as_mut());
      • as_mut() は unsafe 関数です。
      • unsafe 関数を呼び出すには unsafe ブロックが必要です。
  • 実演: コードを修正し(unsafe ブロックを追加し)、再度コンパイルして、 動作するプログラムを示す。

  • 実演: as *mut i32as *mut _ に置き換え、コンパイルできることを示す。

    • このキャストでは、対象の型を部分的に省略できます。Rust コンパイラは、 キャスト元が &mut i32 であることを知っています。この参照型を変換できる ポインタ型は *mut i32 の 1 つだけです。
  • 安全性コメントを追加する:

    • unsafe コードは、責任がコンパイラからプログラマーへ移ることを示す、 と説明しました。
    • unsafe コードを書く際に、この特別な責任について考慮したことをどう伝える のでしょうか。安全性コメントです。
    • 安全性コメントは、unsafe コードがなぜ正しいのかを説明します。
    • 安全性コメントがなければ、unsafe コードは安全ではありません。
  • 議論する: 1 つの大きな unsafe ブロックを使うか、2 つの小さなブロックを 使うか:

    • 複数ではなく、1 つの unsafe ブロックを使うことも可能です。
    • ブロックを分けると、安全性コメントをできるだけ具体的にできます。

推奨される解答

// Copyright 2026 Google LLC
// SPDX-License-Identifier: Apache-2.0

fn main() {
    let mut boxed = Box::new(123);
    let a: *mut i32 = &mut *boxed as *mut i32;
    let b: *mut i32 = std::ptr::null_mut();

    // SAFETY: `a` は i32 への null ではないポインタであり、初期化済みで、
    // 依然として割り当てられています。
    println!("{:?}", unsafe { *a });

    // SAFETY: `b` は null ポインタであり、`as_mut()` はこれを `None` に変換します。
    println!("{:?}", unsafe { b.as_mut() });
}