在Rust中返回新字符串的正确方法

时间:2017-03-28 20:14:55

标签: rust

我只花了一个星期阅读Rust Book,现在我正在开发我的第一个程序,它将文件路径返回到系统壁纸:

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。有人可以向我解释为什么这很糟糕,为什么我不应该这样做?或者也许它在某些情况下并不坏并且没问题?

1 个答案:

答案 0 :(得分:22)

cannot return a &str if you've allocated the String in the function。关于why的进一步讨论,以及它not limited to strings的事实。这使您的选择更容易 :返回String

  

String是堆分配的,并且构建为可变的。

String是堆分配的,因为它们的长度未知。由于该分配仅由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")
}

你会遇到常见的错误消息&#34;借来的价值不够活跃&#34;。这是因为借用的值只存在于方法结束之前,而不是输入字符串切片。你不能欺骗&#34;编译器(如果可以的话,这是一个主要的错误)。