2016-04-24 18 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