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 {}.
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);
}
()
Comparing References
{
let x = 10;
let y = 10;
let rx = &x;
let ry = &y;
let rrx = ℞
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
───╯
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(¶bola);
}
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(¶bola);
│ ────┬────
│ ╰────── 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(¶bola);
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 {}.
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
───╯
Taking Arms Against a Sea of Objects