Moving/Borrowing/Slicing
It is important to understand the data types (i.e., notation) that Rust uses to indicate moving, borrowing or slicing.
- When data is copied or moved, the data type of the new owner variable is the same as the original owner.
- When data is borrowed, the data type of the borrower i.e., the variable you're assigning the reference to, is simply preceded by
&
. - When data is borrowed for mutation, the data type of the borrower i.e., the variable you're assigning the reference to, is simply preceded by
& mut
. - When a String is sliced, the data type of the
String
slice is&str
- When an array is sliced, the data type of the array slice is
&[type]
. E.g. if you obtain a slice of ani32
array, the data type will be&[i32]
. Notice how the slice's data type doesn't contain the size of the array i.e., it is not&[i32; array_size]
The snippet below shows the data type when a variable is moved, borrowed or sliced.
fn main() { //Moving, borrowing or slicing a String let foo_bar: String = String::from("foo bar"); let mut foo_bar2: String = foo_bar; //Moved - so data type is the same a foo_bar which is simply String let foo_bar_ref: &String = &foo_bar2; //Immutable reference to a String and this is denoted by &String let foo_bar_slice: &str = &foo_bar2[..3]; //A String slice - this is denoted by &str println!("{} {} {:?}", foo_bar2, foo_bar_ref, foo_bar_slice); //A mutable reference to a String //This is denoted by & mut String let foo_bar_mut_ref: & mut String = & mut foo_bar2; foo_bar_mut_ref.push_str(" baz"); println!("{}", foo_bar_mut_ref); //Moving, borrowing or slicing arrays let foo_bar:[String; 2] = [String::from("foo"), String::from("bar")]; let mut foo_bar2:[String; 2] = foo_bar; // Moved - so data type is the same a foo_bar which is simply [String; 2] let foo_bar2_ref: &[String; 2] = &foo_bar2; //Immutable reference to an array of String and this is denoted by &[String; 2] //An immutable slice of the array. The data type is simply &[String]. Notice that in this case the array size is not specified. let foo_bar2_slice: &[String] = &foo_bar2[1..]; println!("{:?} {:?} {:?}", foo_bar2, foo_bar2_ref, foo_bar2_slice); //A mutable slice of the array. //The data type is simply & mut [String]. Notice that in this case the array size is not specified. let foo_bar2_slice: & mut [String] = & mut foo_bar2[1..]; foo_bar2_slice[0] = String::from("barbaz"); println!("{:?}", foo_bar2_slice); //A mutable reference to the array let foo_bar2_mut_ref: & mut [String; 2] = & mut foo_bar2; foo_bar2_mut_ref[1].push_str("baz"); foo_bar2_mut_ref[0] = String::from("bay"); println!("{:?}", foo_bar2_mut_ref); }
Although we explicitly set the data types in the snippet above, they can also be derived implicitly as shown in screen shot below
Note: What we've demonstrated with arrays in the example above also applies to collections like vectors, sets which we'll see later on.