SyMind / learning

路漫漫其修远兮,吾将上下而求索。
9 stars 1 forks source link

Rust 将 String 作为切片(&str)返回 #70

Open SyMind opened 1 year ago

SyMind commented 1 year ago

原文:https://stackoverflow.com/questions/29428227/return-local-string-as-a-slice-str

我试图在函数中构建一个 String,然后将其返回为 &str 切片,编译器抛出了错误,因为生命周期太短。我不能直接使用 str,因为我需要动态构建它。但是,我也不想返回一个 String,因为它在构建后应当是静态的。

这是一个无法通过编译的最小复现代码:

fn return_str<'a>() -> &'a str {
    let mut string = "".to_string();

    for i in 0..10 {
        string.push_str("ACTG");
    }

    &string
}

首先,请记住引用是借用,即它们指向某些数据但不拥有它,它属于其他人。在这种特殊情况下,字符串(你要返回的切片)归函数所有,因为它存储在局部变量中。

当函数退出时,它的所有局部变量都被销毁;这会调用析构函数,String 的析构函数释放字符串使用的内存。但是,你想要返回一个借用的引用,指向为该字符串分配的数据。这意味着返回的引用立即变为悬空 - 它指向无效内存!

Rust 是为了防止此类问题而创建的。因此,在 Rust 中,不可能返回指向函数局部变量的引用,而这在 C 等语言中是可能的。

还有一种解释,稍微正式一点。让我们看看你的函数签名:

fn return_str<'a>() -> &'a str

请记住,生命周期参数和通用参数是参数:它们由函数的调用者设置。例如,其他一些函数可能会这样调用它:

let s: &'static str = return_str();

这需要 'a 是 'static,但这当然是不可能的——你的函数不会返回对静态内存的引用,它会返回一个生命周期更短的引用。因此这样的函数定义是不合理的并且被编译器禁止。

无论如何,在这种情况下你需要返回一个拥有类型的值,在这种特殊情况下它将是一个拥有的 String:

fn return_str() -> String {
    let mut string = String::new();

    for _ in 0..10 {
        string.push_str("ACTG");
    }

    string
}