2016-05-23 10 views
2

borrowed value does not live long enoughになるのはなぜですか?以下の例:to_string()は "借用した値が十分に長生していません"というエラーを発生させます

use std::collections::HashMap; 

struct Foo { 
    id: Option<usize>, 
    name: String 
} 

fn main() { 

    let foos = getFoos(); 

    for foo in foos { 
     let mut map = HashMap::new(); 
     map.insert("name", &foo.name); 
     map.insert("id", &foo.id.unwrap().to_string()); 
    } 

} 

fn getFoos() -> Vec<Foo> { 
    Vec::new() 
} 

エラー:

src/main.rs:15:27: 15:54 error: borrowed value does not live long enough 
src/main.rs:15   map.insert("id", &foo.id.unwrap().to_string()); 
             ^~~~~~~~~~~~~~~~~~~~~~~~~~~ 
src/main.rs:13:38: 16:6 note: reference must be valid for the block suffix following statement 0 at 13:37... 
src/main.rs:13   let mut map = HashMap::new(); 
src/main.rs:14   map.insert("name", &foo.name); 
src/main.rs:15   map.insert("id", &foo.id.unwrap().to_string()); 
src/main.rs:16  } 
src/main.rs:15:9: 15:56 note: ...but borrowed value is only valid for the statement at 15:8 
src/main.rs:15   map.insert("id", &foo.id.unwrap().to_string()); 
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
src/main.rs:15:9: 15:56 help: consider using a `let` binding to increase its lifetime 
src/main.rs:15   map.insert("id", &foo.id.unwrap().to_string()); 
         ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 

なぜコンパイラが中間値を作成することが示唆されていますか?このエラーは混乱します。

+0

あなたは 'to_string'によって生成された値を参照しています。 https://play.rust-lang.org/?gist=b41ea549d5b4add70559827b7d41e58a&version=stable&backtrace=0 –

+0

[ローカル文字列をスライス(&str)として返す]の可能な複製(http: //stackoverflow.com/questions/29428227/return-local-string-as-a-slice-str) –

+1

@ker重複しているとは思わない。同様のはい、しかしまだ十分なIMO :) –

答えて

4

&Stringという文字列への参照を保存するHashMapを作成しています。私たちはタイプに注釈を付けるならば、それは次のようになります。

let mut map: HashMap<&str, &String> = HashMap::new(); 

これは、マップがどこかを生きるオブジェクトへの参照を多く含んでいることを意味します。あなたの最初のインサートでは、が他の場所に、具体的にはオブジェクトfooに住んでいるので、完全にうまく動作します。

map.insert("name", &foo.name); 

しかし、あなたの2番目の挿入に問題があります:あなたはどこかに住んでいるStringオブジェクトを、参照したいです。 to_string()は関数によって返されるStringを作成しますが、あなたの場合はそれは単なる一時オブジェクトです。オブジェクトは、行が実行された後に破棄されます。

map.insert("id", &foo.id.unwrap().to_string()); 

コンパイラが正しくあります:letバインディングが問題を解決します。

let mut map = HashMap::new(); 
map.insert("name", &foo.name); 
let id_string = foo.id.unwrap().to_string(); 
map.insert("id", &id_string); 

これはあなたの小さな例ではうまくいきますが、あなたがもっと大きなものを扱っているともっと複雑になる可能性があります。たとえば、HashMapがループの外側で定義されている場合は、マップに挿入する参照が少なくとも地図自体の長さである必要があるため、問題が発生します。

関連する問題