Borrow Checking
Rust’s borrow checker puts constraints on the ways you can borrow values. For a given value, at any time:
- You can have one or more shared references to the value, or
- You can have exactly one exclusive reference to the value.
1. ```
fn main() {
```
2. ```
let mut a: i32 = 10;
```
3. ```
let b: &i32 = &a;
```
5. ```
{
```
6. ```
let c: &mut i32 = &mut a;
```
7. ```
*c = 20;
```
8. ```
}
```
10. ```
println!("a: {a}");
```
11. ```
println!("b: {b}");
```
12. ```
}
```
This slide should take about 10 minutes.
- Note that the requirement is that conflicting references not exist at the same point. It does not matter where the reference is dereferenced.
- The above code does not compile because
ais borrowed as mutable (throughc) and as immutable (throughb) at the same time. - Move the
println!statement forbbefore the scope that introducescto make the code compile. - After that change, the compiler realizes that
bis only ever used before the new mutable borrow ofathroughc. This is a feature of the borrow checker called “non-lexical lifetimes”. - The exclusive reference constraint is quite strong. Rust uses it to ensure that data races do not occur. Rust also relies on this constraint to optimize code. For example, a value behind a shared reference can be safely cached in a register for the lifetime of that reference.
- The borrow checker is designed to accommodate many common patterns, such as taking exclusive references to different fields in a struct at the same time. But, there are some situations where it doesn’t quite “get it” and this often results in “fighting with the borrow checker.”
