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

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

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

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

Q&A

解決済

1回答

1113閲覧

Rustのライフタイムの解決方法

Yhaya

総合スコア439

Rust

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

0グッド

1クリップ

投稿2021/10/28 11:14

編集2021/10/28 11:16

やろうとしていること

Rustからシェルのコマンドを実行して出力を処理するプログラムを書こうと思っています。

環境

  • Windows10
  • Rust 1.55.0

コード

問題が生じているコードは以下のコードです。

rust

1use std::io; 2use std::process::Command; 3use regex::Regex; 4 5struct CondaEnvStatus { 6 is_exist: bool, 7 path: Option<&'static str>, 8} 9 10fn environment_exist() -> Result<CondaEnvStatus, String> { 11 let mut exist = false; 12 let mut env_path = ""; 13 match Command::new("conda").arg("env").arg("list").output() { 14 Ok(output) => { 15 let pattern = Regex::new(r"^thz\s+(.+)").expect("Invalid pattern"); 16 let pathes = String::from_utf8(output.stdout).unwrap(); 17 let lines = pathes.lines(); 18 for line in lines { 19 let cap = pattern.captures(line); 20 match cap { 21 Some(cap) => { 22 exist = true; 23 env_path = &cap[1]; 24 println!("Environment exist in: {}", &cap[1]); 25 break; 26 } 27 None => continue, 28 } 29 } 30 31 if !exist { 32 println!("Vurtural environment for the application does not exist"); 33 } 34 } 35 Err(msg) => { 36 return Err(msg.to_string()); 37 } 38 } 39 40 Ok(CondaEnvStatus { 41 is_exist: exist, 42 path: Some(env_path), 43 }) 44}

このコードの let lines = pathes.lines();env_path = &cap[1]のところで

bash

1`pathes` does not live long enough: assignment requires that `pathes` is borrowed for `'static`

bash

1`cap` does not live long enough: assignment requires that `cap` is borrowed for `'static`

のようなエラーが出ます。2番目に関してはcapのライフタイムがmatch文の中で尽きているのでstaticを付けろということなのだと思うのですが、具体的にどこにstaticを付けたらいいのかわかりません。

よろしくお願いします。

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

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

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

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

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

guest

回答1

0

ベストアンサー

まずは解決法

'staticライフタイムが要求されるのは、CondaEnvStatus構造体のpathフィールドがOption<&'static str>型だからです。

結論からいうとpathフィールドの型をOption<String>型に変更する必要があります。

rust

1struct CondaEnvStatus { 2 is_exist: bool, 3 // pathをOption<&'static str>型からString型へ変更する 4 path: Option<String>, 5}

そしてenvironment_exists()関数内のenv_path変数の型も&strからStringに変えます。これによりコンパイルエラーが解消します。

rust

1fn environment_exist() -> Result<CondaEnvStatus, String> { 2 let mut exist = false; 3 // env_pathを&str型からString型へ変更する 4 let mut env_path = "".to_string(); 5 ... 6 7 match cap { 8 Some(cap) => { 9 exist = true; 10 // cap[1]をString型に変換する 11 env_path = cap[1].to_string(); 12 ... 13 14 Ok(CondaEnvStatus { 15 is_exist: exist, 16 path: Some(env_path), 17 })

なお、余談ですがenv_path変数の型はOption<String>にして、初期値として""ではなくNoneを持たせた方がいいかもしれません。ご質問のコードですと、pathが見つからないときはenv_pathの値が""のままになり、CondaEnvStatuspathフィールドにSome("")がセットされます。が、見つからないときはNoneがセットされた方がわかりやすいと思います。

env_path変数の型をOption<String>にすることで、pathが見つからないときはpathフィールドにNoneがセットされるようになります。

rust

1fn environment_exist() -> Result<CondaEnvStatus, String> { 2 let mut exist = false; 3 // env_pathをOption<String>型にする 4 let mut env_path = None; 5 ... 6 7 match cap { 8 Some(cap) => { 9 exist = true; 10 // cap[1]をOption<String>型に変換する 11 env_path = Some(cap[1].to_string()); 12 ... 13 14 Ok(CondaEnvStatus { 15 is_exist: exist, 16 // ここでは単にenv_pathの値(Option<String>型)をセットする 17 path: env_path, 18 })

なぜ&'static strではダメなのか?

'staticライフタイムを持つ参照は基本的にコンパイル時定数からしか作成できません。&strの場合は文字列リテラルだけが'staticライフタイムを持つことができます。

ご質問のコードでは、実行時に外部コマンドの標準出力から得た文字列(実行時に作られたString)から&strを得ようとしています。このような&str'staticライフタイムを持ちませんので、CondaEnvStatus.path'staticは満たせません。そのためpathフィールドの型を変える必要があります。

ここで、最初に提示したようにOption<String>型にする方法と、

rust

1struct CondaEnvStatus { 2 is_exist: bool, 3 // pathをOption<&'static str>型からString型へ変更する 4 path: Option<String>, 5}

CondaEnvStatusにライフタイム'aを導入して、Option<&'a str>型にする方法があります。

rust

1struct CondaEnvStatus<'a> { 2 is_exist: bool, 3 // pathをOption<&'static str>型から&'a str型へ変更する 4 // ここで'aは、CondaEnvStatus自体のライフタイムよりも長い 5 // ライフタイムを示す 6 path: Option<&'a str>, 7}

もしStringの所有者が他にすでにいて、それがCondaEnvStatusよりも長く生存するなら&'a str型にできます。しかし、今回の場合はそれに該当する所有者はいません。

path: Option<String>として、CondaEnvStatus自体をStringの所有者にするのが自然なやり方になります。こうすることで、StringCondaEnvStatusと同じ期間生存することが保証されます。

投稿2021/10/28 14:15

tatsuya6502

総合スコア2046

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

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

Yhaya

2021/10/29 01:21

ありがとうございます!解決しました。コードのアドバイスまでいただきありがとうございます
tatsuya6502

2021/10/29 01:58

解決してよかったです!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問