error[E0505]: cannot move out of `var` because it is borrowed

参照中の変数を移動しようとした。

注意点

このエラー自体のルールは単純である。

しかし、エラーを読み解くには、参照まわりのその他の知識も必要になる事がある。

例えば、『ライフタイムの延長』の影響があると、初見では納得しにくいエラーになる。

メッセージ

メッセージの構成はだいたい以下のようになる。

要約部
  • 参照中の移動が検出された変数名
詳細部
  • 変数の束縛箇所 ← 問題の変数の導入部
  • 参照の発生個所 ← エラー個所より前方
  • 書込の発生個所 ← エラー個所
  • 参照の使用箇所 ← エラー個所より後方
  • clone の提案

パターン

パターン A1

基本形 (Clone 実装なし)

単純に条件を満たした場合について。

サンプル


fn main() {
    let var = MyType();
    let var_ref = &var;
    var.consume();
    var_ref.use_ref();
}

struct MyType();

impl MyType {
    pub fn consume(self) {}
    pub fn use_ref(&self) {}
}

error[E0505]: cannot move out of `var` because it is borrowed
 --> src\main.rs:4:5
  |
2 |     let var = MyType();
  |         --- binding `var` declared here
3 |     let var_ref = &var;
  |                   ---- borrow of `var` occurs here
4 |     var.consume();
  |     ^^^ move out of `var` occurs here
5 |     var_ref.use_ref();
  |     ------- borrow later used here
  |
note: if `MyType` implemented `Clone`, you could clone the value
 --> src\main.rs:8:1
  |
3 |     let var_ref = &var;
  |                    --- you could clone this value
...
8 | struct MyType();
  | ^^^^^^^^^^^^^ consider implementing `Clone` for this type

パターン A2

基本形 (Clone 実装あり)

前のパターンとほぼ同じだが、Clone を実装済の場合、微妙にメッセージが変わる。

サンプル


fn main() {
    let var = MyType();
    let var_ref = &var;
    var.consume();
    var_ref.use_ref();
}

#[derive(Clone)]
struct MyType();

impl MyType {
    pub fn consume(self) {}
    pub fn use_ref(&self) {}
}

error[E0505]: cannot move out of `var` because it is borrowed
 --> src\main.rs:4:5
  |
2 |     let var = MyType();
  |         --- binding `var` declared here
3 |     let var_ref = &var;
  |                   ---- borrow of `var` occurs here
4 |     var.consume();
  |     ^^^ move out of `var` occurs here
5 |     var_ref.use_ref();
  |     ------- borrow later used here
  |
help: consider cloning the value if the performance cost is acceptable
  |
3 |     let var_ref = &var.clone();
  |                       ++++++++

パターン B

Drop トレイトの影響

詳しくは『Drop トレイトのライフタイムへの影響 - ライフタイムの延長』を参照。
(注: Drop トレイトを直接的に扱っていなくても考慮が必要。)

サンプル


fn main() {
    let var = MyValue(1);
    let _var_ref = var.new_ref();
    var.consume();
}

#[derive(Clone)]
struct MyValue(i32);

impl MyValue {
    fn consume(self) {}

    fn new_ref(&self) -> MyRef<'_> {
        MyRef(&self.0)
    }
}

struct MyRef<'a>(&'a i32);
impl Drop for MyRef<'_> {
    fn drop(&mut self) {
        println!("ID [{}] is drpoped.", self.0)
    }
}

error[E0505]: cannot move out of `var` because it is borrowed
 --> src\main.rs:4:5
  |
2 |     let var = MyValue(1);
  |         --- binding `var` declared here
3 |     let _var_ref = var.new_ref();
  |                    --- borrow of `var` occurs here
4 |     var.consume();
  |     ^^^ move out of `var` occurs here
5 | }
  | - borrow might be used here, when `_var_ref` is dropped and runs the `Drop` code for type `MyRef`
  |
help: consider cloning the value if the performance cost is acceptable
  |
3 |     let _var_ref = var.clone().new_ref();
  |                       ++++++++