Closed6

[Rust] 参照・借用のルール

はっぱはっぱ

#1 すでに誰かが借用している場合、元の値の破棄や所有権移転はできない

Rust
let s1 = String::from("hello");

let r = &s1;  // 参照 `r` を作成
let s2 = s1;  // `s2` へ所有権移転

println!("r: {}", r);  // <-- コンパイルエラー
error[E0505]: cannot move out of `s1` because it is borrowed
# エラー[E0505]: 借用されているため `s1` からムーブはできません
 --> src/main.rs:5:14
  |
4 | let r = &s1;
  |             --- borrow of `s1` occurs here
5 | let s2 = s1;
  |          ^^ move out of `s1` occurs here
             # (2) その前にここで `s1` からムーブされています
6 |
7 | println!("r: {}", r);
  |                   - borrow later used here
                      # (1) ここで借用している(=参照を使っている)にもかかわらず、↑

理由: 参照が指し示している変数がすでに所有権を失っている(=値を持っていない)事態を防ぐため。

はっぱはっぱ

#2 可変参照は同時に 1 つしか持つことができない

Rust
// 可変文字列
let mut s = String::from("hello");

// 可変参照 その 1
let r1 = &mut s;
// 可変参照 その 2
let r2 = &mut s; // <-- コンパイルエラー

println!("{}, {}", r1, r2);
error[E0499]: cannot borrow `s` as mutable more than once at a time
# エラー[E0499]: 可変として `s` を借用することは同時に 1 回しかできません
  --> src/main.rs:8:14
   |
6  |     let r1 = &mut s;
   |              ------ first mutable borrow occurs here
8  |     let r2 = &mut s;
   |              ^^^^^^ second mutable borrow occurs here
                         # 可変としての 2 回目の借用が発生しています
9  |
10 |     println!("{}, {}", r1, r2);
   |                        -- first borrow later used here

理由: 複数の参照でそれぞれ値を変更されてしまうと、コンパイラがそれを追ってチェックできなくなってしまうため。

はっぱはっぱ

#3 初期化されていない変数を借用することはできない

Rust
fn print_string(s2: &String) {
    println!("{}", s2);
}

fn main() {
    // 初期化してない String 型変数
    let s: String;
    print_string(&s);  // <-- コンパイルエラー
}
error[E0381]: borrow of possibly-uninitialized variable: `s`
# エラー[E0381]: 初期化されていないと思われる変数 `s` から借用しています
 --> src/main.rs:8:18
  |
8 |     print_string(&s);
  |                  ^^ use of possibly-uninitialized `s`

理由: #1 と同様、参照が指し示している変数が値を持っていない事態を防ぐため。

はっぱはっぱ

#4 どこも指し示さない(=ダングリング)参照は作成できない

Rust
// 参照を返す関数
fn dangling_fn() -> &String {       // <-- コンパイルエラー
    let s = String::from("hello");
    &s

    // ここで dangling_fn() のスコープが終了して
    // 変数 `s` はドロップ(破棄)されるため、
    // これの参照である `&s` はどこも指さない
}

理由: #1, #3 と同様。

はっぱはっぱ

#5 不変参照がある間は、可変参照を作成できない

let mut s = String::from("hello");

let r1 = &s; // 問題なし
let r2 = &s; // 問題なし
let r3 = &mut s; // 大問題!
error[E0502]: cannot borrow `s` as mutable because it is also borrowed as
immutable
# エラー[E0502]: `s`は不変で借用されているので、可変で借用できません
 --> borrow_thrice.rs:6:19
  |
4 |     let r1 = &s;
  |               - immutable borrow occurs here  # 不変として借用しているのに
5 |     let r2 = &s;
6 |     let r3 = &mut s;
  |                   ^ mutable borrow occurs here  # 可変として借用しています
7 | }
  | - immutable borrow ends here

理由: #2 と同様。

このスクラップは2024/01/01にクローズされました