【问题标题】:Why can I not reverse the result of str::split?为什么我不能反转 str::split 的结果?
【发布时间】:2015-07-06 05:47:04
【问题描述】:

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

【问题讨论】:

    标签: string rust string-parsing


    【解决方案1】:

    其他答案都是正确的,但我想指出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 存在的原因 - 这意味着以一种有效的方式从字符串的末尾开始并拆分到开头。

    【讨论】:

      【解决方案2】:

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

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

      文档列出了哪些类型实现了DoubleEndedSearcher。那里的所有类型都不对应&amp;str 模式,因此在字符串拆分时不能使用rev()

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

      Rust 的这些特性(条件 trait 实现和方法本地的 trait bound)允许编写真正富有表现力的代码,但有时它们可​​能难以通读。

      【讨论】:

      • 不是str 必须实现DoubleEndedSearcher,在这种情况下是StrSearcher。我想。那,或者我在str 上读错了Pattern 的含义...
      【解决方案3】:

      TLDRStrSearcher(搜索字符串模式的类型)没有实现 DoubleEndedSearcher,因此,split 迭代器没有实现 DoubleEndedIterator 和,因此你不能在上面调用rev

      如果您查看该页面上rev 的文档,您将看到where Self: DoubleEndedIterator。这意味着rev 被定义当且仅当Iterator trait 被实现的类型(即Split DoubleEndedIterator 特质。

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

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

      因此,DoubleEndedIterator 是为 Split 实现的实现DoubleEndedSearcher

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

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

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

      type Searcher = StrSearcher<'a, 'b>
      

      快到了!按照链接到documentation for StrSearcher 和...

      ...DoubleEndedSearcher 没有实现。因此,所需的边界得到满足,rev 不能在 Split 迭代器上使用。

      【讨论】:

        猜你喜欢
        • 2021-09-07
        • 1970-01-01
        • 2015-04-22
        • 1970-01-01
        • 2018-12-30
        • 2011-08-22
        • 2021-05-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多