将通用迭代器(例如 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
这是不言自明的。我可以使用底层文件系统分隔符将剩余的组件收集到一个字符串中,但这似乎比实际解决方案更像是一种解决方法。
在更一般的意义上:我们能否将通用迭代器(如 Skip
或 Map
转换回专用迭代器(如 Components
、DirEntry
等) .只要能保证Item类型一样就可以了?
编辑#1:
作为参考,我能想到的从字符串构建新路径的最有效解决方案如下所示(使用不稳定的 intersperse
和 MAIN_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()
的急切方法,因此您必须滚动拥有,就像我一样。
为了避免 XY 问题,这是我最初想做的:
我有一条路径:/foo/bar/bloo/baz/file.txt
并且想要从中获取 bloo/baz/file.txt
的最有效方法,基本上跳过特定组件(在本例中为“bloo”)之前的所有祖先。对我来说最明智的方法是在 std::path::Path.
我的尝试是这样的:
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
这是不言自明的。我可以使用底层文件系统分隔符将剩余的组件收集到一个字符串中,但这似乎比实际解决方案更像是一种解决方法。
在更一般的意义上:我们能否将通用迭代器(如 Skip
或 Map
转换回专用迭代器(如 Components
、DirEntry
等) .只要能保证Item类型一样就可以了?
编辑#1:
作为参考,我能想到的从字符串构建新路径的最有效解决方案如下所示(使用不稳定的 intersperse
和 MAIN_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()
的急切方法,因此您必须滚动拥有,就像我一样。