困るのはだいたい以下のようなコードです。
rust
1fn aaa(n) { 2 for a in b { 3 let c = match fnc() { 4 Some(id) => &id, 5 None => &n 6 }; 7 } 8}
fnc()
により生成されたid
が維持できません。エラー文はerror[E0597]: id does not live long enough
のような形になると思います。よく出現する変数のリファレンスを生成するものの途中で寿命が尽きるというエラーです。
これをlifetimeの修飾によりエラーを回避したいと思います。しかし、どの部分を触ればいいのかわかりません。
何かわかる方は回答の方をよろしくお願いします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答1件
0
ベストアンサー
こんにちは。質問がふわっとしているのでこちらもふわっとしたことしか答えられませんが、それでもよければご覧下さい。
まず、提示されたコードはコンパイルが通らない(引数に型が書かれてない、未定義の変数や関数がある)ので雰囲気から察して修正すると以下のようなコードになります。
rust
1fn aaa(n: i32) { 2 let b = vec![1, 2, 3]; 3 for a in b { 4 let c = match fnc() { 5 Some(id) => &id, 6 None => &n, 7 }; 8 } 9} 10 11fn fnc() -> Option<i32> { 12 Some(0) 13} 14 15fn main() {} 16
これを実行すると確かにE0597が出ます。
error[E0597]: `id` does not live long enough --> lifetime_modifier.rs:5:25 | 4 | let c = match fnc() { | - borrow later stored here 5 | Some(id) => &id, | ^^^- `id` dropped here while still borrowed | | | borrowed value does not live long enough error: aborting due to previous error For more information about this error, try `rustc --explain E0597`.
これをベースに話を進めます。
エラーの原因は、 id
のライフタイムがマッチの腕の中で終わるからです。
rust
1 let c = match fnc() { 2 Some(id) => { 3 &id 4 // idのライフタイムはここで終わる 5 }, 6 None => &n, 7 }; 8 // cはidよりも長生きなのでエラー
これは愚直に書くなら fnc
の返り値をもう少し長くとるようにすればエラーは出なくなります。
rust
1 // 一旦変数を束縛したのでcより長生きする 2 let tmp = fnc(); 3 // &Option<i32> に対するマッチ 4 let c = match &tmp { 5 // Rustコンパイラが空気を読んでくれるのでidの型は &i32 になる 6 Some(id) => id, 7 None => &n, 8 };
&Option<i32>
から &i32
が出てくるのは少しトリッキーなので こちら の記事も参考にしてみて下さい。
上記のコードはref
というキーワードを用いてもう少しスッキりした書き方ができます。
rust
1 let c = match fnc() { 2 Some(ref id) => id, 3 None => &n, 4 };
これが推奨される書き方です。
話が脇道に逸れますが、今回のケースに限っていえば Option::as_ref
とOption::_unwrap_or
を使ってさらに綺麗に書けます。
rust
1 let c = fnc().as_ref().unwrap_or(&n);
これも覚えておいて損はないでしょう。
さて、今回提示されたコードでは上記の回答で問題ありませんが、状況が変わるとエラーになることがあります。
今回は c
は for
式文の中のスコープでのみ有効なので、同じく for
式文の中で生成された fnc
の返り値に束縛できました。これが例えば c
を関数から返そうとするとエラーになります
rust
1fn aaa(n: i32) -> &i32 { 2 let b = vec![1, 2, 3]; 3 for a in b { 4 let c = fnc().as_ref().unwrap_or(&n); 5 if c == &3 { 6 // cを関数から返そうとする 7 return c; 8 } 9 } 10 &0 11}
この場合は多少記法をいじったところでコンパイルが通りません。
C言語でもありがちな誤りですが、 c
は for
式文の中でしか有効でないので、その参照をそれより長生きする関数の外に返そうとしてもエラーになります。
この場合は参照を取らずに値をムーブしてしまうのが正解です。
rust
1// 参照ではなく値そのものを返す 2fn aaa(n: i32) -> i32 { 3 let b = vec![1, 2, 3]; 4 for a in b { 5 let c = match fnc() { 6 Some(id) => id, 7 None => n, 8 }; 9 if c == 3 { 10 return c; 11 } 12 } 13 0 14}
これら2点で恐らく知りたいことはカバーできているとは思いますが、冒頭で述べた通り質問の意図を正確に掴むのが難しいので的外れな回答をしているかもしれません。その場合は遠慮なくおっしゃって下さい。
まとめると以下になります。
ref
を使うとライフタイムエラーは出なくなる- ただしこれも場合によるので、場合によっては参照をとらないことも必要
- 的確な回答を得たいなら正確なコードで質問すべき
以上、参考になれば幸いです。
投稿2020/04/27 07:59
総合スコア468
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。