Implement into_chars for String (original) (raw)

Proposal

Problem statement

Currently there is no owning analog to the chars iterator. In most contexts this has no real effect, as char is Copy, but it disables some cases where one wants to pass ownership of the underlying String along with the iterator.

Motivating example

Implementing the following function requires some gymnastics.

fn get_chars() -> impl Iterator<Item=char> {
    let s = format!("for one reason or another, you have a String");
    s.chars().filter(|c| ['a','e','i','o','u'].contains(c))
    // error[E0597]: `s` does not live long enough
}

Solution sketch

If into_chars existed, the above function would be simple to write.

fn get_chars() -> impl Iterator<Item=char> {
    let s = format!("for a very good reason, you have a String");
    s.into_chars().filter(|c| ['a','e','i','o','u'].contains(c))
}

Alternatives

It is relatively straightforward to write an owning chars iterator outside of std. As a struct:

struct IntoChars {
    string: String,
    position: usize,
}

impl Iterator for IntoChars {
    type Item = char;

    fn next(&mut self) -> Option<char> {
        let c = self.string[self.position..].chars().next()?;
        self.position += c.len_utf8();
        Some(c)
    }
}

As a closure:

fn into_chars(s: String) -> impl Iterator<Item = char> {
    let mut i = 0;
    std::iter::from_fn(move ||
        if i < s.len() {
            let c = s[i..].chars().next().unwrap();
            i += c.len_utf8();
            Some(c)
        } else {
            None
        }
    )
}

Discussion on irlo.