2017-02-23 5 views
3

クロージャーでOptionの内部でまだ借りている間に値が落ちてしまう問題に直面していますが、行っている。説明するために、ここで私が実際に達成しようとしているものの実施例である:借り入れ中にクロージャーやコンビネーター内で値が早すぎます

fn foo() -> Option<String> { 
    let hd = match std::env::home_dir() {          
     Some(d) => d,               
     None => return None,              
    };                   
    let fi = match hd.file_name() {            
     Some(f) => f,               
     None => return None,              
    };                   
    let st = match fi.to_str() {             
     Some(s) => s,               
     None => return None,              
    };                   
    Some(String::from(st)) 
} 

戻り値はOption<String>内の現在のユーザのホームディレクトリのベース名です。

私はコンビネータでこれをリファクタリングして、None => return None,という行を取り除くつもりだと思っていました。

std::env::home_dir()               
    .and_then(|d| d.file_name())            
    .and_then(|f| f.to_str())            
    .map(String::from) 

しかしrustcは、その値をoutlives参照を検出します。

error: `d` does not live long enough 
    --> src/main.rs:33:35 
    | 
33 |   .and_then(|d| d.file_name()) 
    |      -   ^`d` dropped here while still borrowed 
    |      | 
    |      borrow occurs here 
34 |   .and_then(|f| f.to_str()) 
35 |   .map(String::from) 
    |       - borrowed value needs to live until here 

私はOption<&OsStr>内の参照は、タイプPathBufの値をoutlivingされているためこれがあると思います。しかし、私はまだ値がすぐに範囲外に出ることなくこれにアプローチする方法を考え出すのに苦労しています。

私が達成しようとしていることをさらに説明するために、コピー特性を実装するタイプの類似の例を示します。

let x = 42u16.checked_add(1234)            
    .and_then(|i| i.checked_add(5678))          
    .and_then(|i| i.checked_sub(90))           
    .map(|i| i.to_string());             
println!("{:?}", x); // Some("6864") 

これまでの例では、オーナーシップに関するいくつかの点を見落としています。これはOption<PathBuf>で可能ですか?

答えて

2

PathBufをお返ししましたが、home_dir()から返されましたが、依然として参照を使用しようとしています。

私はそこから変数にそれを維持し、仕事になります。

fn foo() -> Option<String> { 
    let path = std::env::home_dir(); 
    path.as_ref() 
     .and_then(|d| d.file_name()) 
     .and_then(|f| f.to_str()) 
     .map(String::from) 

} 

Playground

path.as_ref()へのコールが消費することなく、and_thenの連鎖の出発点としてOption<&PathBuf>を作ります少なくともString::fromまで必要とされるオリジナルのPathBufを所有しています。

2

クリスの答えを広げる:2番目のand_thenから始まるチェーンを最初のand_thenに渡されたクロージャに入れ子にすることで問題を解決することもできます。これは、d(これはPathBufを所有しています)が生き残るまで有効です。

fn foo() -> Option<String> { 
    std::env::home_dir().and_then(|d| { 
     d.file_name() 
      .and_then(|f| f.to_str()) 
      .map(String::from) 
    }) 
} 
関連する問題