Closing Channels in Rust

Here’s the translated Rust code and explanation in Markdown format suitable for Hugo:

Our first example demonstrates how to close channels, which is useful for indicating that no more values will be sent on a channel. This can be used to communicate completion to the channel’s receivers.

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

fn main() {
    let (tx, rx) = mpsc::channel();
    let (done_tx, done_rx) = mpsc::channel();

    // Here's the worker thread. It repeatedly receives
    // from `rx`. We use `rx.recv()` which returns `Result<T, RecvError>`.
    // If the channel has been closed and all values received,
    // `recv()` will return an `Err`.
    thread::spawn(move || {
        loop {
            match rx.recv() {
                Ok(j) => println!("received job {}", j),
                Err(_) => {
                    println!("received all jobs");
                    done_tx.send(()).unwrap();
                    return;
                }
            }
        }
    });

    // This sends 3 jobs to the worker over the channel, then closes it.
    for j in 1..=3 {
        tx.send(j).unwrap();
        println!("sent job {}", j);
    }
    drop(tx); // Close the channel
    println!("sent all jobs");

    // We await the worker using the synchronization approach.
    done_rx.recv().unwrap();

    // Attempting to receive from a closed channel.
    let result = rx.try_recv();
    println!("received more jobs: {}", result.is_ok());
}

To run the program:

$ cargo run
sent job 1
received job 1
sent job 2
received job 2
sent job 3
received job 3
sent all jobs
received all jobs
received more jobs: false

In this Rust example, we use mpsc::channel() to create a multiple producer, single consumer channel. The tx (transmitter) and rx (receiver) are the sending and receiving ends of the channel, respectively.

We spawn a worker thread that continuously receives jobs from the channel. When the channel is closed and all values have been received, rx.recv() will return an Err, signaling that no more jobs will be sent.

In the main thread, we send three jobs to the worker, then close the channel by dropping tx. We then wait for the worker to finish processing all jobs using a separate done channel.

Finally, we attempt to receive from the closed channel using try_recv(). This returns a Result, and we check if it’s Ok to determine if more jobs were received (which should be false as the channel is closed).

The concept of closing channels in Rust is implicit - when all senders (tx) are dropped, the channel is considered closed. This leads naturally to the next topic: iterating over channels.