我正在尝试在Rust中创建一个Git命令。我正在使用clap
参数解析器包进行命令行处理。我希望我的命令为可以使用的目录取一个可选参数。如果命令没有收到选项,它会假定用户主目录。
我知道我可以使用std::env::home_dir
函数获取用户的主目录(如果已设置)但是让我困惑的部分是如何正确使用match
运算符来获取值的路径。这是我一直在尝试的:
use std::env;
fn main() {
// Do some argument parsing stuff...
let some_dir = if matches.is_present("some_dir") {
matches.value_of("some_dir").unwrap()
} else {
match env::home_dir() {
Some(path) => path.to_str(),
None => panic!("Uh, oh!"),
}
};
// Do more things
当我尝试编译时,我收到一条错误消息,说path.to_str()
的活动时间不够长。我知道to_str
返回的值是match
范围的长度,但是如何从必须调用另一个函数的匹配语句中返回一个值?
答案 0 :(得分:2)
path.to_str()
将返回对&str
中包含的内部字符串的path
引用,该内部字符串的有效期仅为path
,位于match
内手臂
您可以使用to_owned
获取该&str
的拥有副本。您必须相应地调整clap
的值,使其在if的两个分支中具有相同的类型:
let some_dir = if matches.is_present("some_dir") {
matches.value_of("some_dir").unwrap().to_owned()
} else {
match env::home_dir() {
Some(path) => path.to_str().unwrap().to_owned(),
None => panic!("Uh, oh!"),
}
};
或者,您可以使用Cow
来避免第一个分支中的副本:
use std::borrow::Cow;
let some_dir: Cow<str> = if matches.is_present("some_dir") {
matches.value_of("some_dir").unwrap().into()
} else {
match env::home_dir() {
Some(path) => path.to_str().unwrap().to_owned().into(),
None => panic!("Uh, oh!"),
}
};
答案 1 :(得分:1)
正在发生的事情是match语句的范围取得PathBuf
返回的env::home_dir()
对象的所有权。然后,您尝试返回对该对象的引用,但该对象不再立即存在。
解决方案是返回PathBuf
而不是对它的引用(或将其转换为String并返回它,而在任何情况下,它必须是拥有数据的某种类型)。您可能必须更改matches.value_of("some_dir").unwrap()
返回的内容,以便两个分支返回相同的类型。
答案 2 :(得分:1)
有一个相当简单的技巧:增加path
的范围(以及它的生命周期),以便你可以参考它。
use std::env;
fn main() {
// Do some argument parsing stuff...
let path; // <--
let some_dir = if matches.is_present("some_dir") {
matches.value_of("some_dir").unwrap()
} else {
match env::home_dir() {
Some(p) => { path = p; path.to_str().unwrap() },
None => panic!("Uh, oh!"),
}
};
// Do more things
}
效率很高,因为path
仅在必要时使用,并且不需要更改程序中的类型。
注意:我在.unwrap()
之后添加了.to_str()
,因为.to_str()
会返回Option
。请注意它返回Option<&str>
的原因是因为并非所有路径都是有效的UTF-8序列。您可能希望坚持Path
/ PathBuf
。