如何在 Rust 中更改 &Path 的第一个祖先?

How do I change a &Path's first ancestor in Rust?

我想更改 &Path 的第一个祖先,可能是通过像这样返回一个新的 PathBuf

fn change_parent(path: &Path, new_parent: &Path) -> PathBuf;

这是我期望它的工作方式。

let old_path = change_root(Path::new("/hello/world.html"), Path::new("/html"));
let new_path = PathBuf::from("/html/world.html");
assert_eq!(old_path, new_path)

我试过 .ancestors()Path::new("/hello/world.html").ancestors(); returns 是 ["/hello/world.html", "/hello", "/"] 上的迭代器,这与我想要的相反。我想要的是 ["/hello/world.html", "hello/world.html", "/world.html"] 这样我就可以轻松地附加一条新路径。

我是否应该在 "(/|\)" 上改用 split 然后替换第一个结果?

使用 Path::components 我想出了这个解决方案:

use std::path::{Component, Path};
use std::{ffi::OsString, path::PathBuf};

let path = Path::new("/tmp/foo.txt");
let mut b: Vec<_> = path.components().collect();

// b[0] is the root directory "/" and b[1] is the
// "tmp" directory.
let html = OsString::from("html");
b[1] = Component::Normal(&html);

let pb: PathBuf = b.iter().collect();

我找不到更简单的方法来执行此操作。 PathPathBuf 实现都基于单个 OsString。因此,对于这两种类型,要访问路径中的各个组件,底层 OsString 需要被某些东西拆分,而 components 是进行拆分的方法。所以,我不认为真的有另一种解决方案。

这是使用 Rust 编程语言社区 (Discord) 上的 conradludgate 提供的 strip_prefix

use std::path::{Path, PathBuf, StripPrefixError}; 

fn replace_prefix(p: impl AsRef<Path>, from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<PathBuf, StripPrefixError> {
  p.as_ref().strip_prefix(from).map(|p| to.as_ref().join(p))
}

(
  replace_prefix("/public/file.html", "/public", "/.html_output"),
  replace_prefix("/public/folder/nested/file.html", "/public", "/.html_output"),
  replace_prefix("/folder/nested/file.html", "/public", "/.html_output"),
)
(Ok("/.html_output/file.html"), Ok("/.html_output/folder/nested/file.html"), Err(StripPrefixError(())))