Mutate array items in loop

I can't get an example of using iter_mut to work. What am I missing?

fn main() {
    let mut colors = ["red", "yellow", "blue"];
    
    for color in colors.iter_mut() {
        *color.make_ascii_uppercase();
    }
}
println!("{}", colors); // expect ["RED", "YELLOW", "BLUE"]

You can't modify string literals, since they are stored in binary and referenced as &str, i.e. through shared reference. To do this, you have to store your strings as owned values, by calling .to_owned() or .to_string().

2 Likes

To be able to mutate it, you need to have a String, not just a &'static str as you get from string literals. Or more precisely, you need a &mut str which is usually obtained by mutably borrowing from a String.

I.e. ["red", "yellow", "blue"] is a [&'static str; 3].

Use e.g. ["red".to_string(), "yellow".to_string(), "blue".to_string()] instead.

Also *color.make_ascii_uppercase() is interpreted as *(color.make_ascii_uppercase()). You probably mean (*color).make_ascii_uppercase() instead, but you don’t actually need to dereference a variable in order to call a method on it, so color.make_ascii_uppercase() is going to work fine.

Finally that println statement is not inside of the main function and you’ll need {:?} to print an array.

1 Like

Thanks! This works:

fn main() {
    let mut colors = ["red".to_string(), "yellow".to_string(), "blue".to_string()];
    
    for color in colors.iter_mut() {
        (*color).make_ascii_uppercase();
    }
    
    println!("{:?}", colors);
}

Yes, but as I said, you’ll usually write

for color in colors.iter_mut() {
    color.make_ascii_uppercase();
}

since on method calls, dereferencing the argument can happen automatically.

1 Like

In general, you can look up how Rust’s "operators" parse here:

Expressions - The Rust Reference

You’ll see that method calls are higher up on the list than unary * (dereferencing), similarly as to how binary * (multiplication) and / are higher up than + and binary -. Thus *x.f() is *(x.f()) and a + b * c is a + (b * c).

1 Like

An idiomatic solution would be something like this:

let colors: Vec<String> = ["red", "yellow", "blue"].iter()
    .map(|s| s.to_uppercase())
    .collect();
3 Likes