A reference lets Rust find and use a value without taking ownership of it. Borrowing creates a reference: `&value` borrows a value, and a parameter such as `art: &Artwork` accepts that borrow rather than moving the artwork into the function. 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);
}
The same artwork is passed to `admire_art` twice because the function accepts a reference instead of taking ownership. section 2.3.1
Two rules keep borrowed access valid:
- A value may have either one mutable reference or any number of immutable references at a time—not both. section 2.3.1
- A reference must point to a valid value. Moving the value while a reference is still needed, or returning a reference to a local value that will be dropped, fails compilation. section 2.3.3
References are values with lifetimes of their own. When a function returns a reference borrowed from an input, the returned reference remains tied to that input. With one borrowed input, Rust can infer the relationship; with multiple borrowed inputs, a lifetime annotation can specify which input the result borrows from. For example, `fn get_value<'a>(numbers: &'a Vec<i32>, s: &str) -> &'a i32` ties the result to `numbers`, not `s`. It does not make the reference live longer than `numbers`. section 4.4.1
A raw pointer also holds a memory address, but unlike a Rust reference it carries no lifetime or ownership information the compiler can use to establish validity. Dereferencing one therefore requires `unsafe`, and the programmer must check that it points to valid memory. In C-facing code, a Rust function can receive `*const c_char` for input and `*mut c_int` for an output value; check untrusted pointers for null before dereferencing them. A null dereference is undefined behavior. section 3.1.1 section 3.2 section 3.2.2
#[no_mangle]
pub extern "C" fn solve(
line: *const c_char, solution: *mut c_int) -> c_int {
if solution.is_null() { #1
return 1;
}
unsafe {
*solution = 1024; #2
}
0
}
The C-compatible `solve` function checks its output pointer for null, then writes through it inside an `unsafe` block. section 3.2.2
















