Borrowing and Ownership in Rust

Slice

Slices

fn main() {
    let mut x = [1, 2, 3, 4, 5];
    let r = &mut x;
    if let Some((first, rest)) = r.split_first_mut() {
        *first = 100;
        rest[0] = 99;
        rest[1] = 98;
    }
    assert_eq!(x, [100, 99, 98, 4, 5])
}

Deref Coersion in Functions

fn main() {
    let v = 5;
    let r = &v;
    let r2 = &r;
    println!("{}, {}", is_five(r), is_five(r2))
}

fn is_five(val: &i32) -> bool {
    *val == 5
}
## true, true

Smart Pointers

Deref Coersion

From The Book:

Deref coercion is a convenience that Rust performs on arguments to functions and methods. Deref coercion converts a reference to a type that implements Deref into a reference to a type that Deref can convert the original type into.

That is to say, deref coersion can convert &T to &U when it needs to (especially when the type of an argument of a function call doesn’t match), if T implements Deref<Target=U>.

The following example shows how, after implementing Deref<Target=T> for MyBox<T>, &MyBox<String> can be converted to &String:

use std::ops::Deref;

struct MyBox<T>(T);

impl<T> MyBox<T> { 
  fn new(x: T) -> MyBox<T> { MyBox(x) } 
}

impl<T> Deref for MyBox<T> { 
  type Target = T;
  fn deref(&self) -> &T { &self.0 }
}

fn hello(name: &str) {
  println!("Hello, {}!", name); 
}

fn main() { 
  let m = MyBox::new(String::from("Rust")); 
  hello(&m); 
  hello(&(*m)); // desugared
  hello(&(*m)[..]); // desugared * 2
}
## Hello, Rust!
## Hello, Rust!
## Hello, Rust!

When the Deref trait is defined for the types involved, Rust will analyze the types and use Deref::deref as many times as necessary to get a reference to match the parameter’s type.

Therefore, in the above case, &MyBox<String> is first coerced into &(*MyBox<String>) = &(*(MyBox<String>.deref())) = &(*(&String)) = s&String, and &String is coerced into &str. This is also why &&&&T behaves like &T, since &(&T) can be coerced to &(&*T) = &T.

Drop

struct CustomSmartPointer {
    data: String,
}

impl Drop for CustomSmartPointer {
    fn drop(&mut self) {
        println!("Dropping CustomSmartPointer with data `{}`!", self.data);
    }
}

fn main() {
    let c = CustomSmartPointer {
        data: String::from("my stuff"),
    };
    let d = CustomSmartPointer {
        data: String::from("other stuff"),
    };
    println!("CustomSmartPointers created.");
}
## CustomSmartPointers created.
## Dropping CustomSmartPointer with data `other stuff`!
## Dropping CustomSmartPointer with data `my stuff`!