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 an i32 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 moving-borrowing-slicing.png

Note: What we've demonstrated with arrays in the example above also applies to collections like vectors, sets which we'll see later on.