The trait `std::iter::ExactSizeIterator` is not implemented

pub fn is_valid_isbn(isbn: &str) -> bool {
    let alphanumeric = isbn
                        .chars()
                        .enumerate()
                        .filter(|(index, c)| (*index == 9 && c == &'X') || c.is_numeric())
                        .map(|(_, character)| {
                            if character == 'X' {
                                Some(10)
                            }else{
                                character.to_digit(10)
                            }
                            
                        })
                        .map(|x| x.unwrap_or(0))
                        .rev();
                       
    println!("Alphanumeric {:?}", alphanumeric.collect::<Vec<_>>() );
    
    }
    

fn main() {
    is_valid_isbn("3-598-21507-A");
    is_valid_isbn("3-598-2X507-9");
    is_valid_isbn("359821507X");
}

I don't know why i am getting this error, I don't even understand what this error actually means.

Compiling playground v0.0.1 (/playground)
error[E0277]: the trait bound `std::str::Chars<'_>: std::iter::ExactSizeIterator` is not satisfied
  --> src/main.rs:15:26
   |
15 |                         .rev();
   |                          ^^^ the trait `std::iter::ExactSizeIterator` is not implemented for `std::str::Chars<'_>`
   |
   = note: required because of the requirements on the impl of `std::iter::DoubleEndedIterator` for `std::iter::Enumerate<std::str::Chars<'_>>`
   = note: required because of the requirements on the impl of `std::iter::DoubleEndedIterator` for `std::iter::Filter<std::iter::Enumerate<std::str::Chars<'_>>, [closure@src/main.rs:5:33: 5:90]>`
   = note: required because of the requirements on the impl of `std::iter::DoubleEndedIterator` for `std::iter::Map<std::iter::Filter<std::iter::Enumerate<std::str::Chars<'_>>, [closure@src/main.rs:5:33: 5:90]>, [closure@src/main.rs:6:30: 13:26]>`
   = note: required because of the requirements on the impl of `std::iter::DoubleEndedIterator` for `std::iter::Map<std::iter::Map<std::iter::Filter<std::iter::Enumerate<std::str::Chars<'_>>, [closure@src/main.rs:5:33: 5:90]>, [closure@src/main.rs:6:30: 13:26]>, [closure@src/main.rs:14:30: 14:48]>`

rev changes the iteration direction, and will stop when both ends meet. The error tells you that the DoubleEndedIterator trait isn't implemented for this iterator.
You may want to collect the result into a Vec to reverse the iterator, and then call rev.

Enumerate can't count backwards unless it knows how many items are in the incoming iterator. Chars doesn't know how many chars it will produce because utf-8 encoded characters have variable length -- it only knows the total byte length of the whole string.

If you know your string is plain ASCII, probably so for ISBN, then you could iterate bytes instead.

1 Like
 .map(|x| x.unwrap_or(0))
                        .collect::<Vec<_>>() 
                        .rev();

This also doesnt work

16  |                           .rev();
    |                            ^^^ method not found in `std::vec::Vec<u32>`
    |
    = note: the method `rev` exists but the following trait bounds were not satisfied:
            `std::vec::Vec<u32>: std::iter::Iterator`
            which is required by `&mut std::vec::Vec<u32>: std::iter::Iterator`
            `[u32]: std::iter::Iterator`
            which is required by `&mut [u32]: std::iter::Iterator`

I mean something like this, although as @cuviper said, since you are checking an ISBN which is probably ASCII, you could work with the bytes instead of chars.

pub fn is_valid_isbn(isbn: &str) -> bool {
    let alphanumeric = isbn
        .chars()
        .enumerate()
        .filter(|(index, c)| (*index == 9 && c == &'X') || c.is_numeric())
        .map(|(_, character)| {
            if character == 'X' {
                Some(10)
            } else {
                character.to_digit(10)
            }
        })
        .map(|x| x.unwrap_or(0))
        .collect::<Vec<_>>()
        .into_iter()
        .rev()
        .collect::<Vec<_>>();

    println!("Alphanumeric {:?}", alphanumeric);
    false
}

You could also just collect it once in the forward direction, then reverse it in place.

Is it optmised solution?
I was wondering if implementing multiple maps implies iterating over loops multiple times?

In general, there's one loop per consumer, i.e. in this case - per collect, no matter how many adapters were used.

So the iterationa over loop is decided by a collect not on the adapaters i.e I can implement multiple maps but they only be run over the whole vector when I collect?

Yes. Iterators are lazy, they only do something if the consumer asks them, and the consumer will query the whole chain at once.

You can also think of this: to iterate over the iterator multiple times, you'd have to clone it before first loop, and then feed the clone to the second loop. But neither map nor collect require the iterator to be clonable.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.