Search code examples
rustmutable

How do I remove characters from a mutable string within a loop?


I am trying to remove some chars in a mutable string within a loop:

fn main() {
    let mut var1 = String::from("BASDFSADLfasLOONBASDFSADLfasLOON");
    let chars: [char; 5] = ['B', 'A', 'L', 'O', 'N'];
    find_balloon(&mut var1, &chars);
}

fn find_balloon<'a>(s: &'a mut String, chars: &'a [char; 5]) {
    for (i, p) in s.char_indices() {
        if chars.iter().any(|&x| x == p) {
            let mut x = s.remove(i);
            println!("{}", x);
        }
    }
}

The error that I get is the following:

error[E0502]: cannot borrow `*s` as mutable because it is also borrowed as immutable
  --> src/main.rs:10:25
   |
8  |     for (i, p) in s.char_indices() {
   |                   ----------------
   |                   |
   |                   immutable borrow occurs here
   |                   immutable borrow later used here
9  |         if chars.iter().any(|&x| x == p) {
10 |             let mut x = s.remove(i);
   |                         ^^^^^^^^^^^ mutable borrow occurs here

Solution

  • You can't remove elements from a string that you're currently iterating on. Instead, just use the filter method of iterators and collect into a string:

    // using a hashset instead of a slice due to hashsets being faster
    // the slice.iter().any approach still works though
    use std::collections::HashSet;
    
    fn find_balloon(s: &mut String, chars: &HashSet<char>) {
        let filtered: String = s.chars().filter(|x| !chars.contains(x)).collect();
        println!("{}", filtered);
    }
    
    fn main() {
        let mut var1 = String::from("BASDFSADLfasLOONBASDFSADLfasLOON");
        let chars: [char; 5] = ['B', 'A', 'L', 'O', 'N'];
        find_balloon(&mut var1, &chars.iter().cloned().collect());
    }