2017-02-23 1 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은 값을 초과하는 참조를 감지합니다.

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의 가치를 오래 살지되기 때문이다 생각 . 그러나 나는 가치가 너무 빨리 벗어나지 않으면 서이 문제에 접근하는 방법을 생각해 내는데 어려움을 겪고있다.

달성하려는 내용을 더 자세히 설명하기 위해 Copy 특성을 구현하는 유형의 유사한 예제가 있습니다.

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()에서 반환되었지만 여전히 참조를 사용하려고한다는 것은 당연합니다.

내가 변수에 보관, 작업 거기에서 것이다 : 사용하지 않고,

path.as_ref()에 대한 호출이 and_then의 체인의 시작 지점과 같은 Option<&PathBuf>하게

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) 원래 소유 한 PathBuf은 적어도 String::from까지 필요합니다.

2

Chris의 답변 확대 : 두 번째 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) 
    }) 
} 
관련 문제