Search code examples
stringruststring-parsing

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


According to the docs for Split, there is a rev method on the result of doing split on a string:

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;
    }
}

I get the following error:

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

Solution

  • The problem is that rev() is defined on the Split iterator only if it implements DoubleEndedIterator, but Split only implements DoubleEndedIterator if the searcher of the pattern you are splitting on satisfies DoubleEndedSearcher:

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

    The documentation lists which types implement DoubleEndedSearcher. None of the types there correspond to &str pattern, so you can't use rev() when you split on string.

    In your particular case, I guess, it is sufficient to change split(":") to split(':') (i.e. split on character instead of string) because the character pattern searcher does implement DoubleEndedSearcher.

    Such features of Rust (conditional trait implementation and trait bounds local to a method) allow writing really expressive code, but they can be sometimes hard to read through.