我试图了解你如何返回非原语(即没有实现的类型Copy).如果返回类似a的内容i32,则该函数会在内存中创建一个带有返回值副本的新值,因此可以在函数范围之外使用它.但是如果您返回的类型没有实现Copy,则不会执行此操作,并且您将获得所有权错误.
我已经尝试使用Box在堆上创建值,以便调用者可以获取返回值的所有权,但这似乎也不起作用.
也许我通过使用我在C#或其他语言中使用的相同编码样式以错误的方式接近它,其中函数返回值,而不是将对象引用作为参数传递并对其进行变更,以便您可以轻松指示所有权在Rust.
以下代码示例无法编译.我相信问题只在迭代器闭包内,但我已经包含了整个函数,以防万一我没有看到.
pub fn get_files(path: &Path) -> Vec<&Path> {
let contents = fs::walk_dir(path);
match contents {
Ok(c) => c.filter_map(|i| { match i {
Ok(d) => {
let val = d.path();
let p = val.as_path();
Some(p)
},
Err(_) => None } })
.collect(),
Err(e) => panic!("An error occurred getting files from {:?}: {}", pa
th, e)
}
}
Run Code Online (Sandbox Code Playgroud)
编译器给出以下错误(我已删除所有行号和无关文本):
error: `val` does not live long enough
let p = val.as_path();
^~~
in expansion of closure expansion
expansion site
reference must be valid for the anonymous lifetime #1 defined on the block...
...but borrowed value is only valid for the block suffix following statement
let val = d.path();
let p = val.as_path();
Some(p)
},
Run Code Online (Sandbox Code Playgroud)
你返回一个值... 返回它.但是,您的签名显示您正在尝试返回对值的引用.当对象将在块的末尾被删除时,您不能这样做,因为引用将变为无效.
在你的情况下,我可能会写一些类似的东西
#![feature(fs_walk)]
use std::fs;
use std::path::{Path, PathBuf};
fn get_files(path: &Path) -> Vec<PathBuf> {
let contents = fs::walk_dir(path).unwrap();
contents.filter_map(|i| {
i.ok().map(|p| p.path())
}).collect()
}
fn main() {
for f in get_files(Path::new("/etc")) {
println!("{:?}", f);
}
}
Run Code Online (Sandbox Code Playgroud)
主要的是该函数返回一个Vec<PathBuf>- 拥有该路径的类型的集合,而不仅仅是对其他人的内存的引用.
在你的代码中,你做到了let p = val.as_path().在这里,val是一个PathBuf.然后你打电话as_path,定义为:fn as_path(&self) -> &Path.这意味着,给一个参考PathBuf,你可以得到一个参考Path ,只要将生活PathBuf的意愿.但是,您试图将该引用保持的时间比vec存在的时间长,因为它将在迭代结束时被删除.