将通用迭代器(例如 SkipWhile)转换回专用迭代器(例如 std::path::Components)

Converting a generic Iterator (e.g. SkipWhile) back to a specialised iterator (e.g. std::path::Components)

为了避免 XY 问题,这是我最初想做的: 我有一条路径:/foo/bar/bloo/baz/file.txt 并且想要从中获取 bloo/baz/file.txt 的最有效方法,基本上跳过特定组件(在本例中为“bloo”)之前的所有祖先。对我来说最明智的方法是在 std::path::Path.

中使用 components 函数

我的尝试是这样的:

let new_path = path
    .components()
    .skip_while(|v| if let Normal(v) = v { v.as_bytes() != b"bloo" } else { true })
    .skip(1)
    .as_path();

但是这会产生以下错误:

error[E0599]: no method named `as_path` found for struct `Skip` in the current scope
   --> src/main.rs:712:14
    |
712 |             .as_path();
    |              ^^^^^^^ method not found in `Skip<SkipWhile<Components<'_>, [closure@src/main.rs:710:25: 710:89]>>`

For more information about this error, try `rustc --explain E0599`.
error: could not compile `bloggers` due to previous error

这是不言自明的。我可以使用底层文件系统分隔符将剩余的组件收集到一个字符串中,但这似乎比实际解决方案更像是一种解决方法。

在更一般的意义上:我们能否将通用迭代器(如 SkipMap 转换回专用迭代器(如 ComponentsDirEntry 等) .只要能保证Item类型一样就可以了?

编辑#1: 作为参考,我能想到的从字符串构建新路径的最有效解决方案如下所示(使用不稳定的 intersperseMAIN_SEPARATOR_STR 功能):

let new_path: String = path
    .components()
    .skip_while(|v| if let Normal(v) = v { v.as_bytes() != b"bloo" } else { true })
    .skip(1)
    .map(|v| v.as_os_str().to_str())
    .intersperse(Some(std::path::MAIN_SEPARATOR_STR))
    .collect::<Option<_>>()
    .ok_or_else(|| /* error reporting of choice */)?;

最简单的方法是急切地使用迭代器:

let mut new_path = path.components();
while let Some(v) = new_path.next() {
    if let Normal(v) = v {
        if v.as_bytes() == b"bloo" { // Can be just `v == "bloo"`
            break;
        }
    }
}
let new_path = new_path.as_path();
不幸的是,

itertools 具有 dropping() 急切 skip() 方法,但没有等同于 skip_while() 的急切方法,因此您必须滚动拥有,就像我一样。