a[a[0]] = 9 doesn’t work in Rust, why?

Fang Jin
4 min readJan 16, 2022
Photo by Kieran Wood on Unsplash

I recently start to learn Rust, and try to apply it in some problem that I have worked before. But I noticed certain things that can be trivial in other languages stops to be a trivial topic. On the contrary, it can be quite difficult.

fn main() {
let mut a = vec![1,2,3,4,5];
a[a[0]] = 9;
println!("{:?", a);
}

Although the above code seems pretty naive, it reads the first element a[0] and use it to write into another element a[1] . If you try to compile it, we got the following error:

error[E0502]: cannot borrow `a` as immutable 
because it is also borrowed as mutable

a[a[0]] = 9;
--^----
| |
| immutable borrow occurs here
mutable borrow occurs here
mutable borrow later used here

I don’t blame you if you have no idea what these borrow means in the error message. Say we just ignore it and try something different.

Fooling around to make it work

Ok, let’s try to print it first and see if we made any syntax mistake:

  println!("{}", a[a[0]]);  // 2

Yes, it’s working. Getting the value from a[a[0]] has no problem.

Ok, let’s try to write to it:

a[1] = 9;  
println!("{}", a[a[0]]); // 9

The code works as well; we first write to one of the element and then read it out.

Here comes the fix by accidentally introducing a new variable i :

  let i = a[0];
a[i] = 9;
println!("{:?}", a[a[0]]); // 9

The above works!! Wow, what a progress! So what have we done? We put a[0] to a local variable, and then use it as an index to write into the vector.

What have we done? Not sure!

Well, I wouldn’t want to sugar code it. If you pick any Rust book, it would tell you the story much better than me. So I wouldn’t go into details to pretend I know what’s going on. I’ll only show you what’s on the surface.

Rust doesn’t allow an immutable borrow and mutable borrow applied to the same value in one scope. a[0] is immutable borrow, since it reads out something; whereas a[0] = 9 is a mutable borrow, since it writes in something. So a[a[0]] = 9 wouldn’t compile at all!

But to a newbie, what is the difference between a[a[0]] and a[i] where i = a[0] . Man, this is hard. To be honest, if you are not prepared for this type of issue, you’ll be stuck in using Rust quite soon, especially if you think you are good at programming using other languages.

Long story short. i holds a new value, because a is a vector of usize (unsigned integer) and taking a value out of the vector using a[0] producing a copy of the value. You could think of this usize as a primitive value in other languages, although Rust does not have many primitive types. Also Rust does not use this word primitive, it only checks if the type implements a Copy trait (and Clone trait) or not. Anyway, for now, just need to know the a[0] is cloned and copied into the local variable i .

Now the problem changes: a[i] = is a mutable borrow but there’s no immutable borrow of a any more. And we see the magic actually happens in let i = a[0]. Is that simple? What happens if we are not dealing with usize type, what if we store an object in the vector. Let’s try it:

fn main() {
let mut a = vec!["abc".to_string()];
let i = a.last();
a.push("def".to_string());
}

Instead of a “primitive” copiable value, we use String type instead. This is exactly what one of the stack overflow ticket mentioned. The compiler shows the same error once again, even after we write the magic let i statement.

The answer is that, because this time i does not get a copied value from a String , it still holds an immutable borrow of a. Then when we go to a.push which is a mutable borrow, we run into the problem again. The ticket also mentions a fix:

  let i = a.last().cloned();

The fix seems giving us the same approach of making i a copy. But this is not same as copying an element content this time. According to the documentation, cloned is to clone an entire iterator of a. That is how i gets to own a different String letting a off owning the vector.

Conclusion

Notice a[a[0]] = 9 statement won’t work in Rust. This is something we really have to understand before using Rust, because we have been writing this type of statement for decades, thus some systematic brain-wash is definitely needed to re-educate us the “correct” way of doing things. Hopefully this is the correct way!

--

--

Fang Jin

#OpenToWork Front-end Engineer, book author of “Designing React Hooks the Right Way” sold at Amazon.