Modifying String inside a Vec<String>

Hello, I'm new to Rust and I want to get acquainted with Data Structures. I created a mutable String Vector and pushed some data in it. But I encounter a problem upon looping through it and changing its content:

use std::io;

fn main() {
    let mut skillset: Vec<String> = Vec::new();
    println!("Please enter your skills, enter STOP when to end:");
    loop{
        let mut input = String::new();
        io::stdin().read_line(&mut input).expect("Invalid Input");
        input = String::from(input.trim());
        if input == "STOP" {break}
        else{
            skillset.push(input);
        }
    }

    for skill in skillset{
        skill = skill.to_uppercase(); //Not working
    }

}

I want to set all String inside the Vector to uppercase.

Thanks.

Can you be more specific about how it isn’t working— What does it do right now? For example, do you get a compile error or do you see incorrect output when you run the program?

Hello, here is the output:

error[E0384]: cannot assign twice to immutable variable `skill`
  --> src/main.rs:17:9
   |
16 |     for skill in skillset{
   |         -----
   |         |
   |         first assignment to `skill`
   |         help: make this binding mutable: `mut skill`
17 |         skill = skill.to_uppercase();
   |         ^^^^^ cannot assign twice to immutable variable

Oh boy, I just understood my mistake, I should have written:

for mut skill in skillset

for skill in skillset.iter_mut() is probably more correct, but mut skill works as well.

for x in my_vec consumes the Vec and you lose ownership of it. It does not change that if you do mut x since that's only changing the mutability of x. You need to do either for x in my_vec.iter_mut() or for x in &mut my_vec.

3 Likes

Boy. Perl and the Unix shells will spoil you for the real languages. Looping over a vector of Strings kicked my butt for a while today. I ended up with the logically named iter_mut() thing. Had to use to_string() to get Strings out of the str type returned from trim() and replace().

fn main() {
    let mut args:Vec<String> = env::args().collect();
    let _junk = args.remove(0);
    println!("{:?}", args);

    for arg in args.iter_mut() {
        *arg = arg.trim().replace(" ", "_").to_string();
        println!("-{}-",arg);
    }

    println!("{:?}", args);
}```

You can skip and trim before accumulating them into a Vec to avoid the need to mutate args after assignment:

fn main() {
    let args: Vec<String> = env::args()
        .skip(1)
        .map(|arg| arg.trim().replace(' ', "_").to_string())
        .collect();
    println!("{:?}", args);
}
1 Like

Excellent snippit. Thanks!

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.