MeWrite Docs

error[E0507]: cannot move out of 'x' which is behind a shared reference

Rustで共有参照から所有権を移動しようとした際のコンパイルエラー

概要

Rustで共有参照(&T)を通じて値の所有権を移動(ムーブ)しようとした際に発生するコンパイルエラーです。共有参照は読み取り専用であり、所有権を奪うことはできません。

エラーメッセージ

error[E0507]: cannot move out of `*x` which is behind a shared reference
  --> src/main.rs:5:5
   |
5  |     *x
   |     ^^ move occurs because `*x` has type `String`, which does not implement the `Copy` trait

原因

  1. 参照からのムーブ: 共有参照を通じて所有権を移動しようとしている
  2. Copy未実装: 型がCopyトレイトを実装していない
  3. 構造体のフィールドアクセス: 参照を通じてフィールドをムーブしようとしている
  4. イテレータ: 参照イテレータから値をムーブしようとしている

解決策

1. clone()を使用

1
2
3
4
5
6
7
fn get_value(x: &String) -> String {
    // Bad: 参照からムーブできない
    // *x

    // Good: クローンを作成
    x.clone()
}

2. 参照を返す

1
2
3
4
5
6
7
8
fn get_value(x: &String) -> &String {
    // 参照をそのまま返す
    x
}

fn get_first(v: &Vec<String>) -> &String {
    &v[0]
}

3. 所有権を受け取る

1
2
3
4
5
6
7
8
9
// Good: 所有権を受け取って返す
fn process(x: String) -> String {
    x
}

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

4. Option::take()やstd::mem::take()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
use std::mem;

struct Container {
    value: Option<String>,
}

impl Container {
    fn take_value(&mut self) -> Option<String> {
        // Optionからtake(NoneをセットしてSomeを取り出す)
        self.value.take()
    }
}

// または std::mem::take
fn take_string(s: &mut String) -> String {
    mem::take(s) // 空のStringを残して元の値を返す
}

5. Vec::remove()やVec::swap_remove()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
fn main() {
    let mut v = vec!["a".to_string(), "b".to_string(), "c".to_string()];

    // Bad: 参照からムーブできない
    // let item = &v[0];
    // let owned = *item;

    // Good: removeで所有権を取得
    let owned = v.remove(0); // インデックス0の要素を削除して返す

    // Good: swap_removeで効率的に削除(順序は変わる)
    let owned = v.swap_remove(0);
}

6. イテレータでinto_iter()を使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
fn main() {
    let v = vec!["a".to_string(), "b".to_string()];

    // Bad: iter()は参照を返す
    // for item in v.iter() {
    //     let owned: String = item; // Error
    // }

    // Good: into_iter()は所有権を移動
    for item in v.into_iter() {
        let owned: String = item; // OK
        println!("{}", owned);
    }
    // v はここで使用不可
}

7. Cow(Clone-on-Write)を使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
use std::borrow::Cow;

fn process(s: Cow<str>) -> String {
    // 必要な場合のみクローン
    s.into_owned()
}

fn main() {
    let owned = String::from("hello");
    let borrowed = "world";

    process(Cow::Borrowed(borrowed));
    process(Cow::Owned(owned));
}

8. マッチでref/ref mutを使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
struct Person {
    name: String,
    age: u32,
}

fn main() {
    let person = Person {
        name: "Alice".to_string(),
        age: 30,
    };

    // Bad: nameをムーブしようとする
    // match person {
    //     Person { name, age } => println!("{}", name),
    // }

    // Good: refで参照としてバインド
    match &person {
        Person { name, age } => println!("{}: {}", name, age),
    }

    // personはまだ使用可能
    println!("{}", person.name);
}

よくある間違い

  • &Vec<T>をイテレートして要素の所有権を得ようとする
  • 構造体の参照からフィールドをムーブしようとする
  • Copy実装型と非Copy型の挙動の違いを忘れる

関連エラー

参考リンク

Rust の他のエラー

最終更新: 2025-12-13