2016-04-24 15 views
0

我想了解如何在Rust中做一些簡單的事情,但我一直在努力結束與借用檢查器的對抗,我不知道爲什麼。我寫了一個簡單的函數,在其中傳遞一個文件名,併爲您提供主目錄中該文件的路徑。這個Rust功能怎麼不起作用?

這裏的程序:

use std::env; 

fn filename_in_homedir(filename: &str) -> Option<&str> { 
    let mut homedir = match env::home_dir() { 
     None => return None, 
     Some(p) => p 
    }; 
    homedir.push(filename); 
    homedir.to_str() 
} 

fn main() { 
    match filename_in_homedir(".ssh/id_rsa.pub") { 
     Some(s) => println!("{}", s), 
     None => println!("Oops can't get it") 
    }; 
} 

當我嘗試構建它,我得到這個錯誤:

$ cargo build 
    Compiling homedir-test v0.1.0 (file:///home/user/code/homedir-test) 
src/main.rs:9:5: 9:12 error: `homedir` does not live long enough 
src/main.rs:9  homedir.to_str() 
        ^~~~~~~ 
src/main.rs:3:56: 10:2 note: reference must be valid for the anonymous lifetime #1 defined on the block at 3:55... 
src/main.rs:3 fn filename_in_homedir(filename: &str) -> Option<&str> { 
src/main.rs:4  let mut homedir = match env::home_dir() { 
src/main.rs:5   None => return None, 
src/main.rs:6   Some(p) => p 
src/main.rs:7  }; 
src/main.rs:8  homedir.push(filename); 
       ... 
src/main.rs:7:7: 10:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 7:6 
src/main.rs: 7  }; 
src/main.rs: 8  homedir.push(filename); 
src/main.rs: 9  homedir.to_str() 
src/main.rs:10 } 
error: aborting due to previous error 
Could not compile `homedir-test`. 

我不明白爲什麼不工作。如果env::home_dir()失敗,則函數返回None。如果成功,則可變變量homedir將獲得其值(這是一個std::path::PathBuf)。此時,homedir變量應屬於filename_in_homedir範圍。下一行修改homedir以將文件名添加到最後,並且此工作正常。最後一行,呼籲.to_str(),returnsOption<&str>本身。

由於我最終返回該記錄指向內部homedir某處&str,也許當filename_in_homedir範圍結束和homedir被刪除,即&str確實太少,這就是爲什麼它拋出這個錯誤?

如何修改此功能以正常工作,我做錯了什麼?

回答

2

Since I'm ultimately returning a &str that's pointing somewhere inside homedir, maybe when the filename_in_homedir scope ends and homedir gets deleted, that &str does too, which is why it's throwing this error?

這是正確的:你想返回一個指針由filename_in_homedir的堆棧幀所擁有的價值,一旦它返回時,指針無效,將被丟棄。您需要退回String,而不是&str。這裏有一種方法:

use std::env; 
use std::borrow::ToOwned; 

fn filename_in_homedir(filename: &str) -> Option<String> { 
    let mut homedir = match env::home_dir() { 
     None => return None, 
     Some(p) => p 
    }; 
    homedir.push(filename); 
    homedir.to_str().map(ToOwned::to_owned) 
} 

fn main() { 
    match filename_in_homedir(".ssh/id_rsa.pub") { 
     Some(s) => println!("{}", s), 
     None => println!("Oops can't get it") 
    }; 
} 
+0

謝謝,這個作品很棒!我想我應該閱讀'std :: borrow',好像我需要經常使用它。 – micah