Iterating over a String and removing chars

I want to iterate over every character in a String using the char_indices() method and while iterating through it removing specific characters.
(This is just a simplified example of what I am really doing)
But I get error E0502 (which I fully understand why).
How can I solve this?

Code

fn main() {
    let mut string = String::from("some 42 test string");
    
    for (idx, character) in string.char_indices() {
        if character.is_numeric() {
            // Do something
            string.remove(idx);
        }
    }
}

(Playground)

Error

4 | for (idx, character) in string.char_indices() {
| ---------------------
| |
| immutable borrow occurs here
| immutable borrow later used here
...
7 | string.remove(idx);
| ^^^^^^^^^^^^^^^^^^ mutable borrow occurs here

You cannot mutate a string that you're iterating over, it doesn't make sense, and this is an archetypal example of how Rust's borrow checker helps you catch bugs. If it were possible, the iterator would skip over bytes[1] because it has no way of knowing the string has changed. And if you were to add characters, it would be even worse because the string might have to be reallocated, leaving the iterator pointing to deallocated memory.

Better just to collect the non-numeric characters to a new string, eg.

let string = String::from("some 42 test string");

let result: String = string
    .chars()
    .filter(|c| !c.is_numeric())
    .collect();

  1. possibly ending up in the middle of a codepoint and yielding garbage ↩ī¸Ž

2 Likes

There's also retain

5 Likes

Oh, completely forgot about retain. Yeah, it's a great solution in this case.