質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

Q&A

解決済

1回答

3720閲覧

Rust: temporary value dropped while borrowed

kexi

総合スコア16

Rust

Rustは、MoFoが支援するプログラミング言語。高速性を維持しつつも、メモリ管理を安全に行うことが可能な言語です。同じコンパイル言語であるC言語やC++では困難だったマルチスレッドを実装しやすく、並行性という点においても優れています。

0グッド

0クリップ

投稿2020/06/22 10:14

最近rustをはじめたばかりです。
変数historyにmain thread,1,2,3,4...と格納したいのですが
以下のコードを書きましたが、コンパイルエラーにどう対処していいかわからず。

エラー temporary value dropped while borrowed

rust

1use std::thread; 2use std::sync::{Arc, Mutex}; 3 4fn main() { 5 let history = Arc::new(Mutex::new(vec!["main thread"])); 6 for i in 1 ..= 10 { 7 let history = Arc::clone(&history); 8 thread::spawn(move || { 9 let mut v = history.lock().unwrap(); 10 (*v).push(&i.to_string()); 11 }); 12 } 13 14 thread::sleep(std::time::Duration::from_secs(2)); 15 println!("{:?}", history); 16}

どなたか教えていただけませんか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

こんにちは。これはRustのライフタイムが絡むところですね。
今回の対象になるのはクロージャ内だけなのでそこを抜き出します。

rust

1{ 2 let mut v = history.lock().unwrap(); 3 (*v).push(&i.to_string()); 4}

&i.to_string() と一気に書かれていますが、これは分けて書くとこう書けます。

rust

1{ 2 let mut v = history.lock().unwrap(); 3 let tmp = i.to_string(); 4 (*v).push(&tmp); 5}

この tmp はブロック内で作られているのでライフタイムがブロックの末尾で終わります。

rust

1{ 2 let mut v = history.lock().unwrap(); 3 let tmp = i.to_string(); 4 (*v).push(&tmp); 5 // tmpはここで終わり 6}

一方 .push(&tmp) では tmp への参照をブロックの外側へ持ち出そうとしています。

rust

1// 外側にあるhistory 2let history = ... 3{ 4 let mut v = history.lock().unwrap(); 5 let tmp = i.to_string(); 6 (*v).push(&tmp); 7 // tmpはここで終わり 8} 9// historyにpushしたtmpへの参照はここまで有効

ブロックを抜けたときにはライフタイムが終わっている値への参照は無効なのでコンパイラがエラーを出しているのです。

参照ではなく値そのものを push するようにすれば問題が解決します。このとき、型が変わるので history の方も修正する必要がでてきます。
結果、コードはこうなります。

rust

1use std::sync::{Arc, Mutex}; 2use std::thread; 3 4fn main() { 5 // Arc<Mutex<&str>> ではなく `Arc<Mutex<String>>` に 6 let history = Arc::new(Mutex::new(vec!["main thread".to_string()])); 7 for i in 1..=10 { 8 let history = Arc::clone(&history); 9 thread::spawn(move || { 10 let mut v = history.lock().unwrap(); 11 // 参照をとらずに値をそのままpushする 12 v.push(i.to_string()); 13 14 // 本筋から逸れますが、 `(*v).push` ではなく `v.push` で十分です。 15 // コンパイラが裏で `(*v)` に変換してくれます。 16 }); 17 } 18 19 thread::sleep(std::time::Duration::from_secs(2)); 20 println!("{:?}", history); 21} 22

もしよく分からないなら、公式ドキュメントの参照と借用スライスが助けになるかもしれません。

投稿2020/06/22 10:56

blackenedgold

総合スコア468

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kexi

2020/06/22 11:03

丁寧に解説していただきありがとうございます。 周囲にRustをかける人がいないので大変助かりました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問