Libraries cannot provide new inabilities. —Mark Miller

use std::collections::HashMap;
type Table = HashMap<String, Vec<String>>;
fn show(table:Table) {
    for (artist,works) in table {
        println!("works by {}",artist);
        for work in works {
            println!("  {}",work);
        }    
    }
}
let mut table = Table::new();
table.insert("Gesualdo".to_string(),
vec!["many madrigals".to_string(),
"Tenebrae Responsoria".to_string()]);
table.insert("Caravaggio".to_string(),
vec!["The Musicians".to_string(),
"The Calling of St. Matthew".to_string()]);
table.insert("Cellini".to_string(),
vec!["Perseus with the head of Medusa".to_string(),
"a salt cellar".to_string()]);

show(table);
works by Gesualdo
  many madrigals
  Tenebrae Responsoria
works by Caravaggio
  The Musicians
  The Calling of St. Matthew
works by Cellini
  Perseus with the head of Medusa
  a salt cellar
fn sort_works(table: &mut Table) {
for (_artist, works) in table {
works.sort();
}
}
let mut table = Table::new();
table.insert("Gesualdo".to_string(),
vec!["many madrigals".to_string(),
"Tenebrae Responsoria".to_string()]);
table.insert("Caravaggio".to_string(),
vec!["The Musicians".to_string(),
"The Calling of St. Matthew".to_string()]);
table.insert("Cellini".to_string(),
vec!["Perseus with the head of Medusa".to_string(),
"a salt cellar".to_string()]);

sort_works(&mut table);

Assigning References

let x = 10;
let y = 20;
let mut r = &x;
if true { r = &y; }
assert!(*r == 10 || *r == 20);
Error: The variable `r` contains a reference with a non-static lifetime so

can't be persisted. You can prevent this error by making sure that the

variable goes out of scope - i.e. wrapping the code in {}.



Error: The variable `r` contains a reference with a non-static lifetime so

can't be persisted. You can prevent this error by making sure that the

variable goes out of scope - i.e. wrapping the code in {}.

image.png

References to References

{
    struct Point { x: i32, y: i32 }
    let point = Point { x: 1000, y: 729 };
    let r: &Point = &point;
    let rr: &&Point = &r;
    let rrr: &&&Point = &rr;
    assert_eq!(rrr.y, 729);
}
()

image.png

Comparing References

{
    let x = 10;
let y = 10;
let rx = &x;
let ry = &y;
let rrx = &rx;
let rry = &ry;
assert!(rrx <= rry);
assert!(rrx == rry);
    assert!(rx == ry); // their referents are equal
assert!(!std::ptr::eq(rx, ry)); // but occupy different addresses

    assert!(rx == rrx); // error: type mismatch: `&i32` vs `&&i32`
assert!(rx == *rrx); // this is okay
}
[E0277] Error: can't compare `{integer}` with `&{integer}`

    ╭─[command_19:1:1]



 13 │     assert!(rx == rrx); // error: type mismatch: `&i32` vs `&&i32`

    │                ─┬  

    │                 ╰── no implementation for `{integer} == &{integer}`

────╯

Borrowing a Local Variable

{
    let r;
    {
        let x = 1;
        r = &x;
    }
    assert_eq!(*r,1);
}
[E0597] Error: `x` does not live long enough

   ╭─[command_20:1:1]



 4 │         let x = 1;

   │             ┬  

   │             ╰── binding `x` declared here

 5 │         r = &x;

   │             ─┬  

   │              ╰── borrowed value does not live long enough

 6 │     }

   │     ┬  

   │     ╰── `x` dropped here while still borrowed

 7 │     assert_eq!(*r,1);

   │     ────────┬───────  

   │             ╰───────── borrow later used here

───╯

image.png

image.png

image.png

Receiving References as Function Arguments

// This code has several problems, and doesn't compile.
static mut STASH: &i32;
fn f(p: &i32) { STASH = p; }
Error: free static item without body

   ╭─[command_21:1:1]



 2 │ static mut STASH: &i32;

   │ ───────────┬──────────┬  

   │            ╰───────────── error: free static item without body

   │                       │  

   │                       ╰── help: provide a definition for the static: ` = <expr>;`

───╯
static mut STASH: &i32 = &128;
fn f(p: &i32) { // still not good enough
unsafe {
STASH = p;
}
}
Error: lifetime may not live long enough

   ╭─[command_22:1:1]



 2 │ fn f(p: &i32) { // still not good enough

   │         ┬  

   │         ╰── let's call the lifetime of this reference `'1`



 4 │ STASH = p;

   │ ────┬────  

   │     ╰────── assignment requires that `'1` must outlive `'static`

───╯
static mut STASH: &i32 = &10;
fn f(p: &'static i32) {
unsafe {
STASH = p;
    println!("{}",STASH);
}
}
static WORTH_POINTING_AT: i32 = 1000;
f(&WORTH_POINTING_AT);
1000
{
    unsafe {
        println!("{}",STASH);
        println!("{}",WORTH_POINTING_AT);
    }
}
10
1000





()

Passing References to Functions

// This could be written more briefly: fn g(p: &i32),
// but let's write out the lifetimes for now.
fn g<'a>(p: &'a i32) {  }
let x = 10;
g(&x);
fn f(p: &'static i32) {  }
let x = 10;
f(&x);
// This fails to compile: the reference &x must not outlive x, but by passing it to f, we
// constrain it to live at least as long as 'static. There’s no way to satisfy everyone here,
// so Rust rejects the code.
fn f(p: &'static i32) {  }

     ^ warning: unused variable: `p`

unused variable: `p`

help: if this is intentional, prefix it with an underscore

_p



warning: unused variable: `p`

unused variable: `p`

help: if this is intentional, prefix it with an underscore

_p



f(&x);

  ^^ borrowed value does not live long enough

let x = 10;

    ^ binding `x` declared here

f(&x);

^^^^^ argument requires that `x` is borrowed for `'static`

`x` does not live long enough

Returning References

fn smallest(v: &[i32]) -> &i32 {
let mut s = &v[0];
for r in &v[1..] {
if *r < *s { s = r; }
}
s
}
// fn smallest<'a>(v: &'a [i32]) -> &'a i32 {  }
let s;
{
let parabola = [9, 4, 1, 0, 1, 4, 9];
s = smallest(&parabola);
}
assert_eq!(*s, 0);
[unused_variables] Error: unused variable: `p`



[E0597] Error: `parabola` does not live long enough

   ╭─[command_42:1:1]



 3 │ let parabola = [9, 4, 1, 0, 1, 4, 9];

   │     ────┬───  

   │         ╰───── binding `parabola` declared here

 4 │ s = smallest(&parabola);

   │              ────┬────  

   │                  ╰────── borrowed value does not live long enough

   │                  │      

   │                  ╰────── cast requires that `parabola` is borrowed for `'static`

 5 │ }

   │ ┬  

   │ ╰── `parabola` dropped here while still borrowed

───╯
{
let parabola = [9, 4, 1, 0, 1, 4, 9];
let s = smallest(&parabola);
assert_eq!(*s, 0); // fine: parabola still alive
}
()

Structs Containing References

// This does not compile.
struct S {
r: &i32
}
let s;
{
let x = 10;
s = S { r: &x };
}
assert_eq!(*s.r, 10); // bad: reads from dropped `x`
[E0106] Error: missing lifetime specifier

   ╭─[command_44:1:1]



 3 │ r: &i32

   │    ┬  

   │    ╰── expected named lifetime parameter

───╯
struct S<'a> {
r: &'a i32
}
{
    let s;
{
let x = 10;
s = S { r: &x };
}
assert_eq!(*s.r, 10); 
}
[unused_variables] Error: unused variable: `p`



[E0597] Error: `x` does not live long enough

    ╭─[command_49:1:1]



  7 │ let x = 10;

    │     ┬  

    │     ╰── binding `x` declared here

  8 │ s = S { r: &x };

    │            ─┬  

    │             ╰── borrowed value does not live long enough

  9 │ }

    │ ┬  

    │ ╰── `x` dropped here while still borrowed

 10 │ assert_eq!(*s.r, 10);

    │ ──────────┬─────────  

    │           ╰─────────── borrow later used here

────╯

Distinct Lifetime Parameters

struct S<'a> {
x: &'a i32,
y: &'a i32
}
{
    let x = 10;
let r;
{
let y = 20;
{
let s = S { x: &x, y: &y };
r = s.x;
}
}
println!("{}", r);
}
[unused_variables] Error: unused variable: `p`



[E0597] Error: `y` does not live long enough

    ╭─[command_56:1:1]



  5 │ let y = 20;

    │     ┬  

    │     ╰── binding `y` declared here



  7 │ let s = S { x: &x, y: &y };

    │                       ─┬  

    │                        ╰── borrowed value does not live long enough



 10 │ }

    │ ┬  

    │ ╰── `y` dropped here while still borrowed

 11 │ println!("{}", r);

    │                ┬  

    │                ╰── borrow later used here

────╯

struct S<'a, 'b> {
x: &'a i32,
y: &'b i32
}
{
    let x = 10;
let r;
{
let y = 20;
{
let s = S { x: &x, y: &y };
r = s.x;
}
}
println!("{}", r);
}
10





()
fn f<'a>(r: &'a i32, s: &'a i32) -> &'a i32 { r } // perhaps too tight
fn f<'a, 'b>(r: &'a i32, s: &'b i32) -> &'a i32 { r } // looser
fn f<b>(r: &'a i32, s: &'b i32) -> &'a i32 { r } 
[E0261] Error: use of undeclared lifetime name `'a`

   ╭─[command_64:1:1]



 1 │ fn f<b>(r: &'a i32, s: &'b i32) -> &'a i32 { r }

   │      │      ─┬  

   │      ╰────────── help: consider introducing lifetime `'a` here: `'a, `

   │              │  

   │              ╰── undeclared lifetime

───╯



[E0261] Error: use of undeclared lifetime name `'b`

   ╭─[command_64:1:1]



 1 │ fn f<b>(r: &'a i32, s: &'b i32) -> &'a i32 { r }

   │      │                  ─┬  

   │      ╰────────────────────── help: consider introducing lifetime `'b` here: `'b, `

   │                          │  

   │                          ╰── undeclared lifetime

───╯



[E0261] Error: use of undeclared lifetime name `'a`

   ╭─[command_64:1:1]



 1 │ fn f<b>(r: &'a i32, s: &'b i32) -> &'a i32 { r }

   │      │                              ─┬  

   │      ╰────────────────────────────────── help: consider introducing lifetime `'a` here: `'a, `

   │                                      │  

   │                                      ╰── undeclared lifetime

───╯



[non_camel_case_types] Error: type parameter `b` should have an upper camel case name

   ╭─[command_64:1:1]



 1 │ fn f<b>(r: &'a i32, s: &'b i32) -> &'a i32 { r }

   │      ┬  

   │      ╰── warning: type parameter `b` should have an upper camel case name

   │      │  

   │      ╰── help: convert the identifier to upper camel case: `B`

───╯

Omitting Lifetime Parameters

struct S<'a, 'b> {
x: &'a i32,
y: &'b i32
}
fn sum_r_xy(r: &i32, s: S) -> i32 {
r + s.x + s.y
}
// fn sum_r_xy<'a, 'b, 'c>(r: &'a i32, s: S<'b, 'c>) -> i32
fn first_third(point: &[i32; 3]) -> (&i32, &i32) {
(&point[0], &point[2])
}
// fn first_third<'a>(point: &'a [i32; 3]) -> (&'a i32, &'a i32)
struct StringTable {
elements: Vec<String>,
}
impl StringTable {
    fn find_by_prefix(&self,prefix:&str) -> Option<&String> {
        for i in 0..self.elements.len() {
            if self.elements[i].starts_with(prefix) {
                return Some(&self.elements[i]);
            }
        }
        None
    }

}
// fn find_by_prefix<'a, 'b>(&'a self, prefix: &'b str) -> Option<&'a String>

Sharing Versus Mutation

let v = vec![4, 8, 19, 27, 34, 10];
let r = &v;
let aside = v; // move vector to aside
r[0]; // bad: uses `v`, which is now uninitialized
[unused_variables] Error: unused variable: `s`



[unused_variables] Error: unused variable: `p`



Error: The variable `r` contains a reference with a non-static lifetime so

can't be persisted. You can prevent this error by making sure that the

variable goes out of scope - i.e. wrapping the code in {}.

image.png

let v = vec![4, 8, 19, 27, 34, 10];
{
let r = &v;
r[0]; // ok: vector is still there
}
let aside = v;
fn extend(vec: &mut Vec<f64>, slice: &[f64]) {
for elt in slice {
vec.push(*elt);
}
}
let mut wave = Vec::new();
let head = vec![0.0, 1.0];
let tail = [0.0, -1.0];
extend(&mut wave, &head); // extend wave with another vector
extend(&mut wave, &tail); // extend wave with an array
assert_eq!(wave, vec![0.0, 1.0, 0.0, -1.0]);

extend(&mut wave, &wave);
assert_eq!(wave, vec![0.0, 1.0, 0.0, -1.0,
0.0, 1.0, 0.0, -1.0])
[unused_variables] Error: unused variable: `s`



[unused_variables] Error: unused variable: `p`



[E0502] Error: cannot borrow `wave` as immutable because it is also borrowed as mutable

   ╭─[command_83:1:1]



 1 │ extend(&mut wave, &wave);

   │ ───┬── ────┬────  ──┬──  

   │    ╰───────────────────── mutable borrow later used by call

   │            │        │    

   │            ╰───────────── mutable borrow occurs here

   │                     │    

   │                     ╰──── immutable borrow occurs here

───╯

image.png

image.png

Taking Arms Against a Sea of Objects

image.png