Further

From a trait to a future that has not run yet.

Eleven programs past the first page: traits, generics, lifetimes, modules, iterators, closures, threads, and async. Each one still has a check you answer here.

Shared behavior

A trait names shared behavior

A trait is a set of methods a type can promise. impl attaches that promise to one type. The call pier.meters() works because Pier implements Meters.

trait Meters {
    fn meters(&self) -> u32;
}

struct Pier {
    span: u32,
}

impl Meters for Pier {
    fn meters(&self) -> u32 {
        self.span
    }
}

fn main() {
    let pier = Pier { span: 12 };
    println!("{}", pier.meters());
}

What to notice. The trait says what a type can do. The impl says how Pier does it. Another struct can implement Meters with a different body.

What is printed?
What happens if you call meters on a struct that has no impl Meters?
Try it

A generic function keeps the type open

wider is written once and used for any type that can be ordered. T stands for that type. PartialOrd is the bound that allows the comparison.

fn wider<T: PartialOrd>(left: T, right: T) -> T {
    if left > right { left } else { right }
}

fn main() {
    println!("{}", wider(4, 12));
}

What to notice. Both arguments share one T, so they must be the same type. The bound is what makes > legal. i32 implements PartialOrd, which is why 4 and 12 are allowed.

What is printed?
What happens if the call is wider(4, "12")?
Try it

A lifetime ties a borrow to its source

choose returns one of the two borrows. The name 'a tells the compiler that the returned reference must not outlive either input. Both strings are still alive when name is printed.

fn choose<'a>(left: &'a str, right: &'a str, take_left: bool) -> &'a str {
    if take_left { left } else { right }
}

fn main() {
    let north = String::from("north");
    let south = String::from("south");
    let name = choose(&north, &south, true);
    println!("{name}");
}

What to notice. 'a is not a value at runtime. It is a promise about how long the borrow lasts. One lifetime on both inputs means the return is allowed to be either of them.

What is printed?
What happens if choose builds a String inside itself and tries to return a borrow of that local?
Try it

A module hides what it does not publish

mod pier nests a scope inside this file. Items are private unless they are pub. main can call label because the function is public. The path is pier::label.

mod pier {
    pub fn label() -> &'static str {
        "north"
    }
}

fn main() {
    println!("{}", pier::label());
}

What to notice. A module can live in this file or in its own file. Privacy is the same either way: the parent can see pub items, and private items stay inside the module.

What is printed?
What happens if pub is removed from label?
Try it

Lists and closures

An iterator walks a list without a loop index

iter lends each item. copied turns &i32 into i32, which is allowed because integers are Copy. filter keeps values greater than 5, and collect builds a new Vec.

fn main() {
    let spans = [3, 12, 7];
    let long: Vec<i32> = spans.iter().copied().filter(|meters| *meters > 5).collect();
    println!("{}", long.len());
}

What to notice. The array itself is unchanged. filter receives a reference to each item, so the closure writes *meters. The type on long is what tells collect which collection to build.

What is printed?
What is spans after this program runs?
Try it

A closure can use the names around it

The vertical bars name the closure's arguments. extra is not an argument. The closure captures it from main and adds it when coat is called.

fn main() {
    let extra = 2;
    let coat = |meters: i32| meters + extra;
    println!("{}", coat(10));
}

What to notice. A closure is a value. This one borrows extra. It can be called like a function, and it still sees the binding it captured.

What is printed?
Where does extra come from inside the closure?
Try it

dyn keeps the trait and forgets the concrete type

Pier and Cable are different structs. Both implement Label. Box<dyn Label> lets one vector hold either, because the box stores a pointer to the value and to the trait's methods.

trait Label {
    fn name(&self) -> &'static str;
}

struct Pier;
struct Cable;

impl Label for Pier {
    fn name(&self) -> &'static str {
        "pier"
    }
}

impl Label for Cable {
    fn name(&self) -> &'static str {
        "cable"
    }
}

fn main() {
    let parts: Vec<Box<dyn Label>> = vec![Box::new(Pier), Box::new(Cable)];
    println!("{}", parts.len());
}

What to notice. dyn Label has no fixed size, so it cannot sit in the vector by itself. The box has a known size. The concrete type is chosen when Box::new runs.

What is printed?
Why is each part stored in a Box?
Try it

Concurrency

join waits for a thread

spawn starts a closure on another thread. The closure returns 12. join waits until that thread finishes and hands the 12 back to main.

use std::thread;

fn main() {
    let handle = thread::spawn(|| 12);
    let meters = handle.join().unwrap();
    println!("{meters}");
}

What to notice. join returns a Result. unwrap takes the Ok value. The closure captures nothing, so it is safe to send to the new thread.

What is printed?
How does main receive the 12?
Try it

A channel moves a value across threads

mpsc::channel builds a sender and a receiver. The new thread owns the sender and sends 12. main receives that message and prints it. send moves the value. It does not share it.

use std::sync::mpsc;
use std::thread;

fn main() {
    let (tx, rx) = mpsc::channel();
    thread::spawn(move || {
        tx.send(12).unwrap();
    });
    let meters = rx.recv().unwrap();
    println!("{meters}");
}

What to notice. mpsc means many senders, one receiver. recv waits until a message arrives. The move on the closure is required because tx is used on the other thread and must not stay in main.

What is printed?
Why does the closure say move?
Try it

Arc and Mutex share one count

Three threads each add one to the same counter. Arc lets them share ownership of the counter. Mutex lets only one of them change it at a time. After every join, the count is 3.

use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let bolts = Arc::new(Mutex::new(0));
    let mut handles = Vec::new();
    for _ in 0..3 {
        let bolts = Arc::clone(&bolts);
        handles.push(thread::spawn(move || {
            let mut count = bolts.lock().unwrap();
            *count += 1;
        }));
    }
    for handle in handles {
        handle.join().unwrap();
    }
    println!("{}", *bolts.lock().unwrap());
}

What to notice. Arc::clone adds an owner. It does not copy the integer. lock waits for the mutex. The inner bolts binding shadows the outer one and is the owner that moves into that thread.

What is printed?
Why does the counter need both Arc and Mutex?
Try it

An async function builds a future

Calling meters does not run its body and does not produce 12. It returns a future, which is a value that describes the work. This program builds that value, prints a line, and drops the future. Nothing polls it, so the body never runs.

async fn meters() -> u32 {
    12
}

fn main() {
    let future = meters();
    println!("future built");
    drop(future);
}

What to notice. await is how async code waits on a future, and it is allowed only inside an async function. main is ordinary, and this program has no executor. An executor is the loop that polls a future until it finishes.

Try it compiles this program. It still does not run the body of meters. Running a future takes an executor, which is a separate crate, and this lesson stays in the standard library.

What is printed?
What does the call meters() produce in main?
Try it