为什么这个 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() ,返回一个Option<&str>本身。

由于我最终返回了一个指向homedir内部某处的&str,也许当filename_in_homedir范围结束并删除homedir时,&str也会这样做,这就是为什么它会抛出此错误?

如何修改此函数以正常工作,我做错了什么?

由于我最终返回了一个指向 homedir 内部某处的 &str,也许当 filename_in_homedir 范围结束并且 homedir 被删除时,&str 也会这样做,这就是它抛出此错误的原因?

这是正确的:您正在尝试返回指向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")
    };
}

最新更新