error[E0716]: temporary value dropped while borrowed

一時的な値が参照中に破棄された。

パターン

パターン A

基本形

殆どの場合、式内の一時的な値は、文末 (セミコロンの位置) で破棄される。

そのため、それ以降にそれに由来する参照を使用するとエラーになる。

サンプル

以下では、一時的な値 Foo::new() の参照を val_ref() でたどり、結果を ref_to_temp に保存している。しかし、一時的な値はその文末ですぐに破棄されてしまう。そのため、以降にその参照にアクセスがあればエラーとなる。


fn main() {
    let ref_to_temp = Foo::new().val_ref();
    println!("Value is {}.", *ref_to_temp);
}

struct Foo {
    val: i32
}

impl Foo {
    fn new() -> Self {
        Self { val: 0 }
    }
    
    fn val_ref(&self) -> &i32 {
        &self.val
    }
}

error[E0716]: temporary value dropped while borrowed
 --> src\main.rs:2:21
  |
2 |     let ref_to_temp = Foo::new().val_ref();
  |                       ^^^^^^^^^^          - temporary value is freed at the end of this statement
  |                       |
  |                       creates a temporary value which is freed while still in use
3 |     println!("Value is {}.", *ref_to_temp);
  |                              ------------ borrow later used here
  |
help: consider using a `let` binding to create a longer lived value
  |
2 ~     let binding = Foo::new();
3 ~     let ref_to_temp = binding.val_ref();

解決策

エラーメッセージの help にある通り、一時的な値をローカル変数に保存する。

パターン B

参照式

参照式 (&x) は必要に応じて現在のスコープに演算対象 (x) を保存する。そのため、一時的な値に由来する参照でも、この場合は基本形のパターンとは異なり、その参照がすぐに使えなくなる事はない。ただし、スコープを超えた利用ではやはりエラーになる。

サンプル

以下では、参照式により一時的な値に由来する Foo::new().val がスコープに保存される。そのため、それを参照する ref_to_temp の使用は妥当である。しかし、関数 use_ref の引数のライフタイムは 'static であるため、その保存期間を超えてしまっている。


fn main() {
    let ref_to_temp = &Foo::new().val;
    use_ref(ref_to_temp);
}

fn use_ref(arg: &'static i32) {
    println!("Value is {}.", *arg);
}

struct Foo {
    val: i32
}

impl Foo {
    fn new() -> Self {
        Self { val: 0 }
    }
}

error[E0716]: temporary value dropped while borrowed
 --> src\main.rs:2:24
  |
2 |     let ref_to_temp = &Foo::new().val;
  |                        ^^^^^^^^^^ creates a temporary value which is freed while still in use
3 |     use_ref(ref_to_temp);
  |     -------------------- argument requires that borrow lasts for `'static`
4 | }
  | - temporary value is freed at the end of this statement

パターン C

Drop トレイトの影響

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

基本形との関係

このパターンは変数をバインドだけして使用しないレアケースで発生する。
変数を使用すると、基本形のパターンのメッセージに変わる。

サンプル

_var を使用すると基本形のパターンのメッセージに変わる


fn main() {
    let _var = temp().my_ref();
}

fn temp() -> MyType {
    MyType(0)
}

struct MyType(i32);
impl MyType {
    pub fn my_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[E0716]: temporary value dropped while borrowed
 --> src\main.rs:2:16
  |
2 |     let _var = temp().my_ref();
  |                ^^^^^^         - temporary value is freed at the end of this statement
  |                |
  |                creates a temporary value which is freed while still in use
3 | }
  | - borrow might be used here, when `_var` is dropped and runs the `Drop` code for type `MyRef`
  |
help: consider using a `let` binding to create a longer lived value
  |
2 ~     let binding = temp();
3 ~     let _var = binding.my_ref();
  |