为什么我不能反转str::split的结果?

Why can I not reverse the result of str::split?

根据 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>>`

问题是 rev() 仅当它实现 DoubleEndedIterator 时才在 Split 迭代器上定义,但 Split 仅在搜索者实现时才实现 DoubleEndedIterator您要拆分的模式的满足 DoubleEndedSearcher:

impl<'a, P> DoubleEndedIterator for Split<'a, P>
where
    P: Pattern<'a>,
    <P as Pattern<'a>>::Searcher: DoubleEndedSearcher<'a>, 

文档列出了哪些类型实现了 DoubleEndedSearcher。 None 的类型对应 &str 模式,所以当你拆分字符串时你不能使用 rev()

在你的特殊情况下,我想,将 split(":") 更改为 split(':') 就足够了(即拆分字符而不是字符串),因为字符模式搜索器 确实 实施 DoubleEndedSearcher.

Rust 的这些特性(条件特征实现和方法局部特征边界)允许编写真正富有表现力的代码,但它们有时可能难以通读。

TLDRStrSearcher(搜索字符串模式的类型)没有实现 DoubleEndedSearcher,因此,split 迭代器没有实现 DoubleEndedIterator,因此,您不能对其调用 rev

如果您查看 rev 页面上的文档,您会看到 where Self: DoubleEndedIterator。这意味着 rev 被定义 当且仅当 正在为 Iterator 特性实现的类型(即 Split实现了DoubleEndedIterator特征。

如果你再往下看,你会看到:

impl<'a, P> DoubleEndedIterator for Split<'a, P>
where P: Pattern<'a>, P::Searcher: DoubleEndedSearcher<'a>

因此,DoubleEndedIteratorSplit 实现当且仅当 这两个条件都满足时:P 必须是 Pattern 和它定义的 Searcher 类型必须实现 DoubleEndedSearcher.

现在,您使用字符串文字作为模式,因此如果您检查 documentation for the str type,您将看到:

impl<'a, 'b> Pattern<'a> for &'b str

其中,关联的 Searcher 类型定义为:

type Searcher = StrSearcher<'a, 'b>

快到了!按照 link 到 documentation for StrSearcher 和...

...DoubleEndedSearcher 没有实现。因此,所需的边界 满足并且 rev 不能用于 Split 迭代器。

其他答案都正确,但我想指出rsplit。这可能更明显,性能更高。

那么,为什么不能使用 rev?正如其他答案所述,它没有为 StrSearcher 实现。但是为什么没有实现呢?来自 DoubleEndedSearcher 文档:

For this, the impl of Searcher and ReverseSearcher need to follow these conditions:

  • All results of next() need to be identical to the results of next_back() in reverse order.
  • next() and next_back() need to behave as the two ends of a range of values, that is they can not "walk past each other".

使用字符串反转迭代器的问题是:

"baaab".split("aa") // -> ["b", "aa", "ab"];

但是,如果您从字符串的末尾开始,您会得到如下内容:

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

这明显不是同一套物品,顺序不同!

简而言之,您不能反转在字符串上拆分的迭代器,因为没有高效知道下一个时间的方法结果是。您必须将整个字符串拆分为一个集合,然后反转该集合!

这就是 rsplit 存在的原因 - 它意味着从字符串的末尾开始并以高效的方式拆分到开头。