Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Can't assign `std::str::Chars` to a variable of type `I: Iterator`

I’m trying to create a custom iterator over a string’s characters, with the difference that it "splits" the string into two iterators. Which one is then used in its own next() depends on custom logic.

struct WrappingIter<I> {
    iter_1: I,
    iter_2: I,
    // ...
}

impl<I> WrappingIter<I>
where
    I: Iterator,
{
    pub fn new(string: &str, start_idx: usize) -> Self {
        Self {
            iter_1: string[start_idx..].chars(),
            iter_2: string[..start_idx].chars(),
            // ...
        }
    }
}

That gives me this error (for both assignments):

 1  error[E0308]: mismatched types
   --> src/lib.rs:38:25
    |
 29 |     impl<I> WrappingIter<I>
    |          - this type parameter
 ...
 38 |                 iter_1: string[start_idx..].chars(),
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `I`, found struct `Chars`
    |
    = note: expected type parameter `I`
                       found struct `Chars<'_>`

I can’t tell why. std::str::Chars implements the Iterator trait, so my logic was that I could directly assign it to WrappingIter‘s members. Need I perhaps perform some sort of cast?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

This line of code can be roughly translated to "For any type I that implements the Iterator trait, define these methods in the following impl block for WrappingIter<I>" in English.

impl<I> WrappingIter<I> where I: Iterator { /* ... */ }

Notice that the type I can be any type that implements Iterator, but in the new method, an iterator of type std::str::Chars (which is not always equal to the type I) is assigned to it, which is why the code snippet fails to compile.


Here’s a solution to make it compile by manually implementing the trait separately for each iterator type. For std::str::Chars, you have to annotate the lifetime explicitly, since the iterator is borrowed from a slice on the argument string. For an alternative solution without generics (and may be more practical), see @Finomnis’s answer.

struct WrappingIter<I> {
    iter_1: I,
    iter_2: I,
}

impl<'i> WrappingIter<std::str::Chars<'i>> {
    pub fn new(string: &'i str, start_idx: usize) -> Self {
        Self {
            iter_1: string[start_idx..].chars(),
            iter_2: string[start_idx..].chars(),
        }
    }
}

// for demo purpose, try with another Iterator type
impl WrappingIter<std::ops::Range<i64>> {
    pub fn new(range: std::ops::Range<i64>) -> Self {
        Self {
            iter_1: range.clone(),
            iter_2: range.clone(),
        }
    }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading