I lost an hour this week to a cannot borrow as mutable because it is also borrowed as immutable error, and I want to record it mainly because of how the hour ended. It ended with me being wrong, which is the usual outcome of fighting the borrow checker.
The shape was the classic one: I was iterating over a collection with an immutable borrow and trying to modify the same collection inside the loop. Push to a Vec while I'm in the middle of reading it. The compiler refused, flatly, and I spent a while resenting it, because in the C I grew up on I'd just do it and hope the reallocation didn't invalidate my pointer mid-loop.
And there it is. The reallocation. If the Vec grows while I'm holding a reference into it, that reference can dangle, because the whole backing buffer may have moved. The borrow checker wasn't being pedantic. It was refusing to let me write the exact bug that would have been a baffling intermittent crash in another language, the kind you only hit when the vector happens to resize on the iteration you cared about.
So I lost gracefully. I collected the changes I wanted to make into a separate Vec inside the loop, then applied them afterwards once the immutable borrow had ended:
let to_add: Vec<_> = items.iter()
.filter(|i| i.needs_partner())
.map(|i| i.make_partner())
.collect();
items.extend(to_add);
Slightly more code, completely safe, and arguably clearer about what it's doing. The borrow checker keeps winning these arguments because it keeps being right, and I'm slowly learning to read its complaints as "you have a bug here" rather than "I am being difficult". So far it has not once been the difficult one.