You cannot use a Box
for this. A box always owns the thing it points at, but the target of second
is owned by mut_tuple
, so it cannot be owned by the box.
You might attempt to use a mutable reference, which does not need to own its target:
fn main() {
let mut mut_tuple = (&mut 5u32, 3u32);
{
let (ref mut first, ref mut second) = mut_tuple;
*first = second;
*second = 2u32;
}
println!("tuple is {:?}", mut_tuple);
}
but it fails:
error[E0506]: cannot assign to `*second` because it is borrowed
--> src/main.rs:6:9
|
5 | *first = second;
| ------ borrow of `*second` occurs here
6 | *second = 2u32;
| ^^^^^^^^^^^^^^ assignment to borrowed `*second` occurs here
7 | }
8 | println!("tuple is {:?}", mut_tuple);
| --------- borrow later used here
This is because mutable references always have exclusive access to the thing they point to for the duration in which the reference is live. A reference is live at least from its creation until its last use, and the creation is at the *first = second;
line, and the last is use the println!
line. This means that accessing second
directly between those two is not allowed, because it would be in contradiction with the fact that first
has exclusive access at that point.
Now, immutable references don't require that the access is exclusive. So maybe we can use that?
fn main() {
let mut mut_tuple = (&5u32, 3u32);
{
let (ref mut first, ref second) = mut_tuple;
*first = second;
*second = 2u32;
}
println!("tuple is {:?}", mut_tuple);
}
this also fails:
error[E0594]: cannot assign to `*second`, which is behind a `&` reference
--> src/main.rs:6:9
|
4 | let (ref mut first, ref second) = mut_tuple;
| ---------- help: consider changing this to be a mutable reference: `ref mut second`
5 | *first = second;
6 | *second = 2u32;
| ^^^^^^^^^^^^^^ `second` is a `&` reference, so the data it refers to cannot be written
Immutable references must be immutable for the entire duration in which it is live. Therefore, we cannot modify second
while the immutable reference in first
is alive.
So how can we fix this? Well, there's a special type called Cell
that can let us do this:
use std::cell::Cell;
fn main() {
let mut mut_tuple = (&Cell::new(5u32), Cell::new(3u32));
{
let (ref mut first, ref second) = mut_tuple;
*first = second;
second.set(2u32);
}
println!("tuple is {:?}", mut_tuple);
}
tuple is (Cell { value: 2 }, Cell { value: 2 })
Why does this work? Well, the Cell
type is special in the following way: Even if the contents change, the cell is not considered to have been modified. This means that we can actually modify it, even though we only have an immutable reference to the cell.
To read more, see:
- The documentation for
std::cell::Cell
.
- This article on Cell: Temporarily opt-in to shared mutation
Note that Cell
is a simple version of RefCell
, which you may have heard of.