MeWrite Docs

error[E0382]: borrow of moved value

Rustで所有権が移動した後の値を借用しようとした際のコンパイルエラー

概要

Rustで値の所有権が別の変数や関数に移動(ムーブ)した後に、その元の値を借用または使用しようとした際に発生するコンパイルエラーです。

エラーメッセージ

error[E0382]: borrow of moved value: `s`
  --> src/main.rs:5:20
   |
2  |     let s = String::from("hello");
   |         - move occurs because `s` has type `String`, which does not implement the `Copy` trait
3  |     let s2 = s;
   |              - value moved here
4  |
5  |     println!("{}", s);
   |                    ^ value borrowed here after move

原因

  1. 変数への代入: 値を別の変数に代入すると所有権が移動
  2. 関数への引数渡し: 関数に値を渡すと所有権が移動
  3. クロージャでのキャプチャ: moveクロージャで値がキャプチャされる
  4. Copy未実装: 型がCopyトレイトを実装していない

解決策

1. clone()で複製

1
2
3
4
5
6
7
fn main() {
    let s = String::from("hello");
    let s2 = s.clone(); // クローンを作成

    println!("{}", s);  // OK: sはまだ有効
    println!("{}", s2);
}

2. 参照を渡す

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
fn print_length(s: &String) {
    println!("Length: {}", s.len());
}

fn main() {
    let s = String::from("hello");
    print_length(&s); // 参照を渡す

    println!("{}", s); // OK: sの所有権は維持
}

3. 所有権を返す

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
fn process(s: String) -> String {
    println!("Processing: {}", s);
    s // 所有権を返す
}

fn main() {
    let s = String::from("hello");
    let s = process(s); // 所有権を渡して返してもらう

    println!("{}", s); // OK
}

4. Copy型を使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
fn main() {
    // Copy型(i32, f64, bool, charなど)
    let x = 42;
    let y = x; // コピーされる

    println!("{}", x); // OK: xはまだ有効
    println!("{}", y);
}

// カスタム型にCopyを実装
#[derive(Copy, Clone)]
struct Point {
    x: i32,
    y: i32,
}

5. Rcで共有所有権

1
2
3
4
5
6
7
8
9
use std::rc::Rc;

fn main() {
    let s = Rc::new(String::from("hello"));
    let s2 = Rc::clone(&s); // 参照カウントを増加

    println!("{}", s);  // OK
    println!("{}", s2); // OK
}

6. クロージャでの対処

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
fn main() {
    let s = String::from("hello");

    // Bad: moveでsの所有権が移動
    // let closure = move || println!("{}", s);
    // println!("{}", s); // Error

    // Good: クローンをmove
    let s_clone = s.clone();
    let closure = move || println!("{}", s_clone);

    println!("{}", s); // OK
    closure();
}

7. スコープを分離

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
fn main() {
    let s = String::from("hello");

    {
        let s2 = &s; // 借用
        println!("{}", s2);
    } // s2の借用が終了

    let s3 = s; // 所有権を移動

    println!("{}", s3); // OK
    // println!("{}", s); // Error
}

8. Option::take()で所有権を取得

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
fn main() {
    let mut opt = Some(String::from("hello"));

    // 所有権を取得しつつOptionをNoneに
    if let Some(s) = opt.take() {
        println!("{}", s);
    }

    println!("{:?}", opt); // None
}

Copy型とMove型

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// Copy型: スタックに固定サイズで格納、コピーされる
// - i8, i16, i32, i64, i128, isize
// - u8, u16, u32, u64, u128, usize
// - f32, f64
// - bool
// - char
// - タプル(要素がすべてCopy型の場合)
// - 配列(要素がCopy型の場合)

// Move型: ヒープを使用、所有権が移動する
// - String
// - Vec<T>
// - Box<T>
// - その他ヒープアロケーションを含む型

よくある間違い

  • 関数に値を渡した後で元の変数を使おうとする
  • forループで値をイテレートした後でコレクションを使う
  • if letやmatchで値をムーブした後で使おうとする

関連エラー

参考リンク

Rust の他のエラー

最終更新: 2025-12-13