[Rust] Borrow checker

Three rules:

  1. There can only be one value owner
  2. There can be unlimited immutable borrows (reference) with no mutable references
  3. There can be only one mutable reference and no immuntable references

 

There is one rule for lifetimes

  1. 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);
}

 

posted @ 2023-05-29 14:42  Zhentiw  阅读(31)  评论(0编辑  收藏  举报