references and borrowing in rust
1. terminology
- a pointer is a variable that contains an address to a location in memory
- we can use
&
to create a reference. A reference is a pointer that only borrows the value it points to. When the reference goes out of scope, the value it points to will not be dropped. - should I think about Rust references in the same way that I think about Pointers in C?
2. String example
fn main(){ let mut s1 = String::from("my_new_string"); takes_reference(&mut s1); } fn takes_reference(s: &mut String){ print("{:?}", s); }
What's going on:
s1
is a smart pointer which means it implements theDrop
trait. So whens1
goes out of scope, the heap locations it points to will be dropped.s
is a reference tos1
. It is also a pointer. But it points to the location in memory wheres1
lives (it's on the stack). Whens
goes out of scope,s1
is not dropped, becauses
is a borrow.
3. int example
fn main(){ let mut i1 = 5i32; takes_reference(&mut i1); } fn takes_reference(i: &mut i32){ *i += 1; print("{:?}", i); }
What's going on:
i1
is an integer valuei
points to the location where the integer value is (it's on the stack)- if we want to add to the integer, we need to de-reference
i
to get at the value it points to - when
i
goes out of scope, the integer value isn't dropped. (Well it wouldn't be dropped anyways, because it's not on the heap)
4. examples
I can't do this:
let s2 = String::from("new_string"); let s5 = &s2; let s6 = s2; print!("{}", s5); print!("{}", s6);
Because s5 points to the String smart pointer, if that smart pointer gets invalidated, then s6 will point to potentially invalidated data. And we need s6 after this invalidation happens.
5. returning
I can return a String and pass ownership to the caller:
fn give_ownership(s: &String) -> String{ let local_string = String::from("my_new_string"); return local_string; }
But I can't give a reference to a local string that I create in the function:
fn give_reference(s: &String) -> &String{ let local_string = String::from("my_new_string"); return &local_string; }
6. lifetimes
- is it possible that the lifetime of the returned reference will ever be longer than the lifetime of the input references?
- I don't think so? How would the returned value be able to go out of scope without the parameters going out of scope first?
7. questions
- I think my weakest point is understanding how
mut
and ownership apply to members of struct and members of a list.
7.1. structs and mutability
- If I want to mutate a struct's member, then I need to have declared that struct mutable when I created it. The
mut
applies to all the struct at once. (see rust book)- And I either need to have ownership of that struct OR a mutable reference to that struct
let mut my_struct = MyStruct::new(3); let my_struct_ref = &mut my_struct; my_struct_ref.inside_string.push_str("ab");
Above: I use a mutable reference to the struct to mutate its member