ライフタイムと借用: 抽象的なルール

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

// 保持しておく何かを用意するための内部データ型。
pub struct Internal;
// 「外側」のデータ。
pub struct Data(Internal);

fn shared_use(value: &Data) -> &Internal {
    &value.0
}
fn exclusive_use(value: &mut Data) -> &mut Internal {
    &mut value.0
}
fn deny_future_use(value: Data) {}

fn demo_exclusive() {
    let mut value = Data(Internal);
    let shared = shared_use(&value);
    // let exclusive = exclusive_use(&mut value); // ❌🔨
    let shared_again = shared;
}

fn demo_denied() {
    let value = Data(Internal);
    deny_future_use(value);
    // let shared = shared_use(&value); // ❌🔨
}

fn main() {}
  • この例は、借用チェッカーのルールを参照から切り離し、 メモリ安全性以外の文脈における意味論的な意味へと捉え直したものです。

    何かが変更されているわけでも、何かがスレッド間で送られているわけでもありません。

  • Rust の借用チェッカーでは、値を「取得」する 3 つの異なる方法を利用できます。

    • 所有値 T。別のスコープに返されない限り、スコープの終了時に値は破棄されます。

    • 共有参照 &T。エイリアシングを許可しますが、共有参照が使用中である間は可変アクセスを禁止します。

    • 可変参照 &mut T。ある時点で 1 つの値に対して存在できるのは 1 つだけですが、共有参照を作成するために使用できます。

  • 問い: demo 関数内のコメントアウトされた 2 行は、なぜコンパイルエラーを引き起こすのでしょうか?

    demo_exclusive: exclusive 参照が取得されたあとも shared 値が依然としてエイリアスされているためです。

    demo_denied: &value から shared_again_again 参照が取得される 1 行前に、value が消費されているためです。

  • すべての &T&mut T にはライフタイムがあることを覚えておいてください。多くの場合、ユーザーが注釈を付けたり意識したりしなくてよいだけです。

    Rust コンパイラでは多くの場合ライフタイムを 省略 できるため、私たちがライフタイムを明示することはまれです。参照: ライフタイム省略