Start learning free

LESSON 102 OF 414 · ARRAYS I

Updating Vector Elements in Rust: Index Assignment and +=

Lesson Read the full explanation

The entries of vectors are mutable and can be changed freely, using indices and the bracket notation, just like we do with static arrays:

let mut names = vec!["Andy", "Mary", "Cody"];

names[0] = "Mircea";
names[2] = "Mike";

// names is now ["Mircea", "Mary", "Mike"]

Assignment
Follow the Coding Tutorial and let's play with some arrays.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 2
    Ctrl + Enter to check

    RUST · ARRAYS I

    Updating Elements in Rust, explained

    What it is and when to use it

    A Vec is Rust's growable list. Once it exists, you can replace any element in place by writing to its index. This is the everyday way to correct a value, update a counter stored at a position, or fill in a table that was created in advance.

    Two things make Rust's version different from many languages. The vector itself must be declared mutable, and the new value must have exactly the element type of the vector. The compiler checks both before the program runs.

    The syntax

    Write the index in square brackets on the left of =. Indexes start at 0, so the first element is at index 0:

    let mut names = vec!["Andy", "Mary", "Cody"];
    
    names[0] = "Mircea";
    names[2] = "Mike";
    
    println!("{:?}", names);

    This prints:

    ["Mircea", "Mary", "Mike"]

    The assignment overwrites the old value. The vector keeps its length, and the other elements are untouched.

    Compound assignment

    For numbers, the compound operators +=, -=, *= and the rest read the current value, combine it with the right-hand side and store the result back at the same index:

    let mut scores = vec![10, 20, 30];
    scores[1] += 5;
    scores[2] *= 2;
    println!("{:?}", scores);
    [10, 25, 60]

    That is shorter than scores[1] = scores[1] + 5 and names the position only once.

    Gotchas in Rust

    The vector must be mut

    Bindings are immutable by default. If you declare let names = vec![...] without mut and then assign to names[0], the compiler rejects the program: it says it cannot borrow the vector as mutable because the binding is not declared as mutable, and it suggests adding mut. Add the keyword to the let and the error disappears.

    The value must match the element type

    A vector holds one type. A vector built from "mango".to_string() holds owned String values, and a string literal such as "apple" is a &str, a different type. Assigning "apple" to an element of a Vec<String> fails with a "mismatched types" error that says it expected String and found &str. Calling .to_string() on the literal produces an owned String and fixes it.

    The same rule applies to numbers: you can't store a string in a vector of integers, or a decimal number in a vector of i32.

    The index must exist

    Assigning to an index does not grow the vector. If the vector has four elements, writing to index 4 or beyond panics at run time with an "index out of bounds" message, instead of silently extending the list. To add an element at the end, use push.

    When an index might be invalid, get_mut is the checked alternative. It returns an Option holding a mutable reference, and None when the index is out of range, so you can write through it only when the element exists:

    let mut v = vec![1, 2, 3];
    if let Some(x) = v.get_mut(1) {
        *x = 20;
    }
    if let Some(x) = v.get_mut(7) {
        *x = 70; // never runs: index 7 doesn't exist
    }
    println!("{:?}", v);
    [1, 20, 3]

    The lesson's exercise

    The starter code gives two mutable vectors: fruits, holding owned String values, and ages, holding integers. The exercise has two steps.

    1. Replace the first fruit. The first item sits at index 0, so assign to fruits[0]. Because the elements are String, the new value is "apple".to_string(), not the bare literal.
    2. Add 5 to the second age. The second item sits at index 1, so ages[1] += 5 turns 32 into 37.

    Here is the complete code:

    let mut fruits = vec!["mango".to_string(), "kiwi".to_string(), "grapefruit".to_string()];
    let mut ages = vec![14, 32, 50, 21];
    
    fruits[0] = "apple".to_string();
    ages[1] += 5;

    Afterwards fruits is ["apple", "kiwi", "grapefruit"] and ages is [14, 37, 50, 21]. Both declarations were already let mut, which is why the edits compile.

    Key takeaways

    • Assign to an element with v[i] = value; indexes start at 0.
    • Use v[i] += n and the other compound operators to update a number in place.
    • The binding must be declared with let mut.
    • The new value must have the vector's element type, so a Vec<String> needs a String, not a &str.
    • Assigning to an index that doesn't exist panics; it never grows the vector.
    Keep going with RustAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free