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

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

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

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

Q&A

解決済

2回答

1764閲覧

Rust 文字列連結でライフタイムのエラー

Watching

総合スコア56

Rust

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

1グッド

1クリップ

投稿2021/09/25 09:30

Rustの練習のために数独を作ろうとしています。とりあえず基本的構造を作り、ToStringトレイトを実装しようとしています。

エラー内容

error[E0716]: temporary value dropped while borrowed

コード

Rust

1struct Grid{ 2 placed_number:Option<u8>, 3 } 4 struct NumberPlace{ 5 field:[[Grid;9];9], 6 } 7 8 impl ToString for NumberPlace{ 9 fn to_string(&self) -> String{ 10 let mut text = String::new(); 11 for x in 0..self.field.len(){ 12 for y in 0..self.field[x].len(){ 13 text += match self.field[x][y].placed_number{ 14 Some(v) => &v.to_string(),//error[E0716]: temporary value dropped while borrowed 15 None => " ", 16 }; 17 } 18 text += "\n"; 19 } 20 text 21 } 22 }

&v.to_string() がmatchの中でドロップしてしまっていることが原因でエラーが発生していると認識していますが、これはどのように解決すれば良いでしょうか?

sutonea👍を押しています

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

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

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

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

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

guest

回答2

0

&v.to_string() がmatchの中でドロップしてしまっていることが原因でエラーが発生していると認識していますが、

その通りです。

いきなり話が脱線しますが、実はRustではToStringを実装することは推奨されておらず、代わりにstd::fmt::Displayを実装することが推奨されています。(Displayを実装すると、自動的にToStringも実装されます)

https://doc.rust-lang.org/stable/std/string/trait.ToString.html

ToString shouldn’t be implemented directly: Display should be implemented instead, and you get the ToString implementation for free.

Displayを実装する際は自分でStringを構築する必要はなく、フォーマッターに対してprint! マクロに良く似たwrite!で書き込みます。その方法ですと今回のご質問のようなライフタイムのエラーには遭遇しないですみます。

とはいえ、ご質問のエラーも、別の、いろいろな場面で遭遇するはずですので、まずはご質問のコード(ToString)のまま解決する方法を紹介して、そのあと、Displayを実装するコードをお見せします。

解決方法1

&v.to_string() がmatchの中でドロップしてしまっていることが原因

&strmatchの外に持ち出せないのならmatchの中でtextに追記してしまえば解決します。

変更前

rust

1text += match self.field[x][y].placed_number{ 2 Some(v) => &v.to_string(),//error[E0716]: temporary value dropped while borrowed 3 None => " ", 4};

変更後

rust

1match self.field[x][y].placed_number { 2 // match内でtextに追記すればライフタイムのエラーが起こらない 3 Some(v) => text += &v.to_string(), 4 None => text += " ", 5};

text += が2回繰り返されるので、あまりかっこいいやり方でないのはたしかです。

解決方法2

そもそも元のコードで&v.to_string()としているのは、Noneのときに&strを返したいので、それに合わせるためだったと思います。std::borrow::Cowで包むことで&strのような借用する値とStringのような所有する値を1つの型に統一できます。

rust

1let s: Cow<'_, str> = match self.field[x][y].placed_number { 2 // StringをCow::Owned(..) に変換する 3 Some(v) => v.to_string().into(), 4 // &'static strをCow::Borrowed(..)に変換する 5 None => " ".into(), 6}; 7text += &s;

Displayを実装する

Displayを実装する場合は以下のようなコードになります。なおご質問のコードではforループを配列のインデックスxyで回していますが、以下のように直接配列の要素を得る方が簡潔なコードになり、Rustらしい書き方になります。

rust

1use std::fmt; 2 3impl fmt::Display for NumberPlace { 4 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 5 // lineは1行分のデータ。&[Grid; 9]型 6 for line in &self.field { 7 // cellは1マス分のデータ。&Grid型 8 for cell in line { 9 match cell.placed_number { 10 // print!マクロによく似たwrite!マクロでフォーマッターに書く 11 Some(v) => write!(f, "{}", v)?, 12 None => write!(f, " ")?, 13 }; 14 } 15 writeln!(f)?; 16 } 17 Ok(()) 18 } 19}

投稿2021/09/25 10:57

tatsuya6502

総合スコア2035

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

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

Watching

2021/09/25 11:10

回答ありがとうございます。 for inで回してないのは後から3行ごとに区切り線を入れて見やすくしようと思ってたからです。インデックスをinで取得する方法もあると聞きましたが上手くいきませんでした。
tatsuya6502

2021/09/25 11:13

なるほどー。そういう場合はenumerate()を使います。以下のようにすると、xにインデックスが入ります。 for (x, line) in self.field.iter().enumerate() {
Watching

2021/09/25 11:25 編集

field.enumerate()で取得できるのかと思っていました。助かります。
guest

0

ベストアンサー

&v.to_string() がmatchの中でドロップしてしまっていることが原因でエラーが発生している

正確には、v.to_string()で作られたStringがmatchの中でドロップしているのに、その参照である&strmatchの外に持ち出そうとしているのでエラーになっています.

修正方法としては、以下のようにmatchから実体であるStringを返すようにすればよいです.

rust

1text += &match self.field[x][y].placed_number { 2 Some(v) => v.to_string(), 3 None => " ".to_string(), 4};

投稿2021/09/25 10:26

編集2021/09/25 10:29
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問