有时候,例如,当读取某些配置文件时,您将读取用户输入的文件路径而无需通过外壳程序(例如,您得到body:
Column(
children: [
Text('foo'),
Expanded(
child: Container(
child: ListView.builder(
shrinkWrap: true,
itemBuilder: .......,
itemCount: .....,
),
),
),
Text('bar')
]
)
,
)。
由于下面的~/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);
}
来简化示例。生产代码中应该有一些错误处理。
答案 0 :(得分:4)
最惯用的方法是仅使用现有的板条箱,在这种情况下,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("~") {
if p == Path::new("~") {
dirs::home_dir()
} else {
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
}
})
}
} else {
Some(p.to_path_buf())
}
}
用法示例:
#[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
的原因
输入,例如&str
,&OsStr
和&Path
。Path::new
不分配任何内容,它指向
与&str
完全相同的字节。strip_prefix("~/").unwrap()
应该永远不会失败,
因为我们检查了路径以~
开头,
不只是~
。唯一的方法是
路径以~/
开头(由于starts_with
已定义)。