[Rust] Borrow checker
Three rules:
- There can only be one value owner
- There can be unlimited immutable borrows (reference) with no mutable references
- There can be only one mutable reference and no immuntable references
There is one rule for lifetimes
- A reference cannnot outlive its value
Example
#[derive(Debug)]
struct MyStruct {
age: usize
}
fn main() {
let mut items: Vec<&MyStruct> = vec![];
{
let item = MyStruct {age: 0};
items.push(&item); // item does not live long enough borrowed ..
}
println!("{:?}", items); // borrow later used here
}
Stated differently
- One var owns the data
- One var can change the data
- Many vars can look at the data
- You cannot look and change the data simultaneously
- You cannot refer to something that has been dropped (released in memory)
Example:
#[derive(Debug)]
struct Item {
count: usize
}
fn add_one(mut item: Item) {
item.count += 1;
}
fn main() {
let item = Item {count: 1};
println!("{:?}", item);
add_one(item);
println!("{:?}", item);
}
// let item = Item {count: 1}; this line owns the item
// add_one(items); move the ownership to add_one function
// println!("{:?}", item); this line will cause error because item is moved to add_one function
Next step:
fn add_one(item: &Item) {
item.count += 1;
}
// item.count += 1; not mutable
fn main() {
let item = Item {count: 1};
println!("{:?}", item);
add_one(&item);
println!("{:?}", item);
}
Now we pass the reference. But now get not mutable error
Next step:
fn add_one(item: &mut Item) {
item.count += 1;
}
fn main() {
let item = Item {count: 1};
println!("{:?}", item);
add_one(&item); // error, consider mutably borrowing here: `&mut item`
println!("{:?}", item);
}
Next step:
fn add_one(item: &mut Item) {
item.count += 1;
}
fn main() {
let item = Item {count: 1};
println!("{:?}", item);
add_one(&mut item); // error: cannot borrow `item` as mutable, as it is not declared as mutable
println!("{:?}", item);
}
Next step:
fn add_one(item: &mut Item) {
item.count += 1;
}
fn main() {
let mut item = Item {count: 1};
println!("{:?}", item);
add_one(&mut item);
println!("{:?}", item);
}
Practic
- Create a function called print_all that takes in an immutable borrow (reference) to items and prints each item, one at a time;
in main function
- create a vector of Items call items
- grab a mutable reference to item 0 (get_mut)
- print item 0
- call print_all
- print item 0 (you have to code this all)
fn print_all(items: &Vec<Item>){
for item in items {
println!("{:?}", item);
}
}
fn main() {
let mut items = vec![Item {count: 1}];
let mut first = items.first_mut();
println!("{:?}", first);
print_all(&items);
// println!("{:?}", first); // you cannot do it here because first is already moved to print_all function
}
- get a mutable reference named one, get_mut(0)
- get mutable reference named two, get_mut(1)
- println!(?{:?}", one)
fn main() {
let mut items = vec![Item {count: 1}];
let first = items.get_mut(0);
let second = items.get_mut(1); // you cannot hold two mutable references at the same time
}
fn main() {
let items = vec![1,2,3] // vec![1,2,3] temporary value ends here
.iter()
.map(|x| x + 1);
println!("{:?}", items);
}
Fix:
fn main() {
let data = vec![1,2,3]
let items = data
.iter()
.map(|x| x + 1);
println!("{:?}", items);
}