Rust allows the owner of a value to lend out that value to others, without giving up ownership, through references.
References are pointers that come with an additional contract for how they can be used, such as
&T
, is, as the name implies, a pointer that may be shared.fn cache(input: &i32, sum: &mut i32) {
*sum = *input + *input;
assert_eq!(*sum, 2 * *input);
}
&mut T
.fn noalias(input: &i32, output: &mut i32) {
if *input == 1 {
*output = 2;
}
if *input != 1 {
*output = 3;
}
}
let x = 42;
let mut y = &x; // y is of type &i32
let z = &mut y; // z is of type &mut &i32
In this example, you are able to change the value of the pointer y to a different value (that is, a different pointer) by making it reference a different variable, but you cannot change the value that is pointed to (that is, the value of x).
Similarly, you can change the pointer value of y through z, but you cannot change z itself to hold a different reference.
The primary difference between owning a value and having a mutable reference to it is that the owner is responsible for dropping the value when it is no longer necessary.
Apart from that, you can do anything through a mutable reference that you can if you own the value, with one caveat:
fn replace_with_84(s: &mut Box<i32>) {
// this is not okay, as *s would be empty:
// let was = *s;
/*1 - cannot move value out here since
caller will try to free at 5 causing double drop
*/
// but this is:
let was = std::mem::take(s);
/*2 - โ to std::mem::replace(&mut value, Default::default());
The default is a separate, owned value, so it is safe
for the caller to drop it when the scope ends at 5.
*/
// so is this:
*s = was;
/*3 - if you donโt need the old value behind the reference,
you can overwrite it with a value that you already own 3,
leaving it to the caller to drop the value later.
*/
// we can exchange values behind &mut:
let mut r = Box::new(84);
std::mem::swap(s, &mut r);
/* 4 - if you have two mutable references, you can swap
their values without owning either of them since
both references will end up with a legal owned
value for their owners to eventually free.
*/
assert_ne!(*r, 84);
}
// 5
let mut s = Box::new(42);
replace_with_84(&mut s);
Some types provide interior mutability, meaning they allow you to mutate a value through a shared reference.
These types usually rely on additional mechanisms or invariants to provide safe mutability without relying on the semantics of exclusive references.
two categories:
those that let you get a mutable reference through a shared reference eg Mutex, RefCell - which contain safety mechanisms to ensure that, for any value they give a mutable reference to, only one mutable reference (and no shared references) can exist at a time.