liveBook · Manning

Borrowing

As explained in Refactoring to Rust

Rust's borrowing rules constrain the number, mutability, and validity of references to a value.

Passing a value to a function can move ownership into that function. If you try to pass the same artwork again, Rust reports a use-of-moved-value error. Borrowing lets the function use the artwork without taking ownership: change its parameter from `Artwork` to `&Artwork`, then call it with `&art1`. section 2.1 section 2.3.1

Two rules govern references:

  • A value may have exactly one mutable reference or any number of immutable references at a time. section 2.3.1
  • References must remain valid. A borrow is temporary; it does not give the borrower ownership or permission to destroy the value. section 2.3.1
Listing 2.9 A program admiring the same art twice
struct Artwork {
  name: String,
}

fn admire_art(art: &Artwork) {  #1
  println!("Wow, {} really makes you think.", art.name);
}

fn main() {
  let art1 = Artwork { name: "The Ordeal of Owain".to_string() };

  admire_art(&art1);  #2
  admire_art(&art1);
}

Compare the borrowed parameter, `art: &Artwork`, with both calls to `admire_art(&art1)`. Neither call moves the artwork, so the second call works. section 2.3.1

The rules also matter when Rust receives a pointer from C. Before turning an NGINX request pointer into a reference, check that it is nonnull and points to an initialized value. While Rust holds an immutable reference, another thread must not mutate that value. A pointer carries no lifetime information, so creating a reference also requires reasoning about how long the pointed-to data remains available. section 4.4

unsafe extern "C" fn read_body_handler(r: *mut ngx_http_request_t)
{
  if r.is_null() {
    eprintln!("got null request in body handler");
    return;
  }

  let request = &*r;

  let body = match request_body_as_str(request) {
    Ok(body) => body,
    Err(e) => {
      eprintln!("failed to parse body: {}", e);
      return;
    }
  };

  eprintln!("Read request body: {:?}", body);
}

The request handler checks `r.is_null()` before using `&*r` to borrow the request, then passes that reference to the body-reading function. section 4.4

How Refactoring to Rust covers it

How deep it goes
Defines reference-count, mutability, and validity rules, then applies them to a moved-value error and an unsafe pointer conversion.
Examples
Uses repeated artwork viewing and an NGINX request-body handler to show ordinary borrowing and checked pointer conversion.
What it assumes
Introduces ownership and borrowing through a small Cargo application rather than assuming prior knowledge of Rust’s ownership system.
What you can do after
Practice/perform it by passing artwork by reference and checking pointer validity before borrowing an NGINX request.
How it connects
Connects borrowing to ownership, moves, mutable and immutable references, lifetimes, and foreign function interfaces.

Also explained in

Compare how 3 books explain borrowing →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Refactoring to Rust. The section links point to the parts of the book it draws on.