2017-03-28 43 views
6

返回一個新的字符串,我只花了一個星期的閱讀書鏽,現在我正在我的第一個程序,它返回的文件路徑,以系統壁紙:適當的方式在拉斯特

pub fn get_wallpaper() -> &str { 
    let output = Command::new("gsettings"); 
    // irrelevant code 
    if let Ok(message) = String::from_utf8(output.stdout) { 
     return message; 
    } else { 
     return ""; 
    } 
} 

我我得到錯誤expected lifetime parameter on &str,我知道Rust想要一個輸入&str,它將作爲輸出返回,因爲在函數內部創建的任何&str將在函數結束後立即清除。

我知道我可以通過返回String而不是&str來回避這個問題,很多類似問題的答案都是這樣說的。但我也似乎可以這樣做:

fn main() { 
    println!("message: {}", hello_string("")); 
} 

fn hello_string(x: &str) -> &str { 
    return "hello world"; 
} 

獲得&str我的功能。有人可以向我解釋爲什麼這是不好的,爲什麼我不應該這樣做?或者在某些情況下,這可能並不壞,好嗎?

+2

我真的不知道如何避免這種情況。您可以嘗試通過預先分配緩衝區來降低成本,但有人必須擁有此內存。在從命令輸出中讀取字符串之前,您無法知道字符串的長度。在堆上分配對我來說是有意義的。 – bluejekyll

+0

@bluejekyll我已經澄清了我的問題,以展示一種看似可以通過簡單地提供一個虛擬參數來獲得終身功能的方法。 – eiko

回答

10

cannot return a &str if you've allocated the String in the function。關於why以及not limited to strings這一事實有進一步的討論。這讓你的選擇多了更簡單:返回String

String s是堆分配和構建爲可變的。

String s是堆分配的,因爲它們具有未知長度。由於該分配完全由String所有,這就是賦予字符串變異的能力。

我的函數只是返回一個文件路徑供參考,我寧願留給調用者來決定它們是否需要一個堆存儲的可變字符串。

這是不可能的。您的功能已執行分配。如果您沒有將分配返回給調用者,則必須釋放該值以防止內存泄漏。如果在釋放後返回,那將是一個無效的參考,導致內存安全違規。

但我也似乎可以這樣做:

fn hello_string(x: &str) -> &str { 
    return "hello world"; 
} 

獲得&str我的功能。有人可以向我解釋爲什麼這個 是壞的,爲什麼我不應該這樣做?或者,在某些情況下, 可能並不壞,可以嗎?

這不是,它只是沒有真正讓你做你在原來的情況下,想要的東西。 "hello world"是一個&'static str,它是一個存儲在程序本身代碼中的字符串片段。它有一個固定的長度,並知道比main壽命更長。

簽名fn hello_string(x: &str) -> &str可以擴展到fn hello_string<'a>(x: &'a str) -> &'a str。這表示生成的字符串切片必須具有與輸入字符串相同的生命週期。一個靜態字符串的生命週期將超過,所以這是有效的替代。

這將爲其中結果僅基於輸入字符串的函數是有用的:

fn long_string(x: &str) -> &str { 
    if x.len() > 10 { 
     "too long" 
    } else { 
     x 
    } 
} 

然而,在你的情況下,該功能擁有String。如果你試圖返回一個參照String,完全無關的輸入字符串:

fn hello_string(x: &str) -> &str { 
    &String::from("hello world") 
} 

你會遇到的常見錯誤消息「借來的價值不活足夠長的時間」。這是因爲借用的值只能在方法結束之前存在,而不會與輸入字符串片段一樣長。你不能「欺騙」編譯器(或者如果你可以的話,那是一個重大的bug)。