习惯性地在 Rust Path 中展开波浪号
Posted
技术标签:
【中文标题】习惯性地在 Rust Path 中展开波浪号【英文标题】:Expand tilde in Rust Path idiomatically 【发布时间】:2019-06-13 12:33:29 【问题描述】:有时,例如在读取某个配置文件时,您无需通过 shell 即可读取用户输入的文件路径(例如,您会得到~/test
)。
由于下面的Option 2
不会写入用户主目录中的测试文件,我想知道是否有比Option 1
更惯用的东西。
use std::env::var;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
fn write_to(path: &Path)
let mut f = File::create(path).unwrap();
f.write_all("Hi".as_bytes()).unwrap();
fn main()
// Option 1
let from_env = format!("/test", var("HOME").unwrap());
let with_var = Path::new(&from_env);
// Create $HOME/test
write_to(with_var);
// Option 2
let with_tilde = Path::new("~/test");
// Create the test file in current directory, provided a directory ./~ exists
write_to(with_tilde);
注意:此处使用unwrap()
以保持示例简短。生产代码中应该有一些错误处理。
【问题讨论】:
【参考方案1】:最惯用的方法是只使用现有的 crate,在这种情况下 shellexpand
(github, crates.io) 似乎可以满足您的需求:
extern crate shellexpand; // 1.0.0
#[test]
fn test_shellexpand()
let home = std::env::var("HOME").unwrap();
assert_eq!(shellexpand::tilde("~/foo"), format!("/foo", home));
或者,您可以尝试使用dirs
(crates.io)。这是一个草图:
extern crate dirs; // 1.0.4
use std::path::Path, PathBuf;
fn expand_tilde<P: AsRef<Path>>(path_user_input: P) -> Option<PathBuf>
let p = path_user_input.as_ref();
if !p.starts_with("~")
return Some(p.to_path_buf());
if p == Path::new("~")
return dirs::home_dir();
dirs::home_dir().map(|mut h|
if h == Path::new("/")
// Corner case: `h` root directory;
// don't prepend extra `/`, just drop the tilde.
p.strip_prefix("~").unwrap().to_path_buf()
else
h.push(p.strip_prefix("~/").unwrap());
h
)
用法示例:
#[test]
fn test_expand_tilde()
// Should work on your linux box during tests, would fail in stranger
// environments!
let home = std::env::var("HOME").unwrap();
let projects = PathBuf::from(format!("/Projects", home));
assert_eq!(expand_tilde("~/Projects"), Some(projects));
assert_eq!(expand_tilde("/foo/bar"), Some("/foo/bar".into()));
assert_eq!(
expand_tilde("~alice/projects"),
Some("~alice/projects".into())
);
一些备注:
P: AsRef<Path>
输入类型模仿标准
图书馆有。这就是为什么该方法接受所有Path
-like
输入,例如 &str
、&OsStr
和 &Path
。
Path::new
没有分配任何东西,它指向
与&str
完全相同的字节。
strip_prefix("~/").unwrap()
绝对不能在这里失败,
因为我们检查了路径是否以~
开头并且
不仅仅是~
。唯一的办法就是这样
路径以~/
开头(因为starts_with
已定义)。
【讨论】:
以上是关于习惯性地在 Rust Path 中展开波浪号的主要内容,如果未能解决你的问题,请参考以下文章