为什么我无法反转str::split的结果?

10
根据Split文档,对于在字符串上执行split操作的结果也有一个rev方法:
fn main() {
    let mut length = 0;
    let mut mult = 1;
    for part in "1:30".split(":").rev() {
        length += mult * part.parse::<i32>().unwrap();
        mult *= 60;
    }
}

我遇到了以下错误:

error[E0277]: the trait bound `std::str::pattern::StrSearcher<'_, '_>: std::str::pattern::DoubleEndedSearcher<'_>` is not satisfied
 --> src/main.rs:4:35
  |
4 |     for part in "1:30".split(":").rev() {
  |                                   ^^^ the trait `std::str::pattern::DoubleEndedSearcher<'_>` is not implemented for `std::str::pattern::StrSearcher<'_, '_>`
  |
  = note: required because of the requirements on the impl of `std::iter::DoubleEndedIterator` for `std::str::Split<'_, &str>`

error[E0277]: the trait bound `std::str::pattern::StrSearcher<'_, '_>: std::str::pattern::DoubleEndedSearcher<'_>` is not satisfied
 --> src/main.rs:4:17
  |
4 |     for part in "1:30".split(":").rev() {
  |                 ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::str::pattern::DoubleEndedSearcher<'_>` is not implemented for `std::str::pattern::StrSearcher<'_, '_>`
  |
  = note: required because of the requirements on the impl of `std::iter::DoubleEndedIterator` for `std::str::Split<'_, &str>`
  = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Rev<std::str::Split<'_, &str>>`
3个回答

14
其他答案是正确的,但我想指出 rsplit。这可能更明显且更高效。
那么,为什么不能使用 rev?像其他答案所述,它没有被实现为 StrSearcher。但是,为什么没有实现呢?从DoubleEndedSearcher文档中可以看到:
“为此,SearcherReverseSearcher的impl需要遵循以下条件:
所有next()的结果都需要与以相反顺序执行的next_back()的结果相同。 next()next_back()必须像一系列值的两端一样行事,也就是说,它们不能“互相越过彼此”。”
使用字符串反转迭代器的问题在于:
"baaab".split("aa") // -> ["b", "aa", "ab"];

然而,如果你从字符串的末尾开始,你会得到类似于:

"baaab".split("aa").rev() // -> ["b", "aa", "ba"]

很明显,这不是一个不同顺序的相同项集合!

简单地说,如果字符串被分割,你不能反转迭代器,因为没有一种有效的方式知道下一个结果是什么。你需要将整个字符串拆分成一个集合,然后才能对该集合进行反转!

这就是为什么rsplit存在的原因 - 它的意思是从字符串末尾开始向开头拆分,并以一种高效的方式执行操作。


12
问题在于,只有当Split实现了DoubleEndedIterator时,rev()才被定义在Split迭代器上,但是只有当用于分割的模式的搜索器满足DoubleEndedSearcher时,Split才实现DoubleEndedIterator
impl<'a, P> DoubleEndedIterator for Split<'a, P>
where
    P: Pattern<'a>,
    <P as Pattern<'a>>::Searcher: DoubleEndedSearcher<'a>, 

文档列出了哪些类型实现了DoubleEndedSearcher。其中没有任何类型对应于&str模式,因此当您在字符串上拆分时无法使用rev()
在您的特定情况下,我猜只需将split(":")更改为split(':')(即根据字符而不是字符串拆分)就足够了,因为字符模式搜索器确实实现了DoubleEndedSearcher
Rust的这些特性(条件特征实现和限制特征局部于方法)允许编写非常表达性的代码,但有时可能很难阅读。

不是 str 需要实现 DoubleEndedSearcher,而是在这种情况下需要实现的是 StrSearcher。我想是这样的。或者我对 str 上的 Pattern 实现理解有误... - DK.

2
TLDR: StrSearcher(执行字符串模式搜索的类型)没有实现DoubleEndedSearcher,因此,split迭代器没有实现DoubleEndedIterator。因此,您无法在其上调用rev
如果您查看该页面上关于rev的文档,您会看到where Self: DoubleEndedIterator。这意味着仅当实现Iterator特性的类型(即Split)还具有DoubleEndedIterator特性的实现时,才定义了rev
如果您继续向下查看,您将看到:
impl<'a, P> DoubleEndedIterator for Split<'a, P>
where P: Pattern<'a>, P::Searcher: DoubleEndedSearcher<'a>

因此,仅当以下两个条件都满足时,DoubleEndedIterator 才会为 Split 实现: P 必须是一个 Pattern,并且它定义的 Searcher 类型必须实现 DoubleEndedSearcher
现在,您正在使用字符串字面量作为模式,因此如果您查看 str 类型的文档 ,您会看到:
impl<'a, 'b> Pattern<'a> for &'b str

在其中,相关的Searcher类型被定义为:

type Searcher = StrSearcher<'a, 'b>

快要完成了!请点击链接查看StrSearcher的文档,但是...DoubleEndedSearcher没有实现。因此,必需的边界得到满足,所以rev不能用于Split迭代器。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接