Rust Guide > Documentation > Concurrency > Receiver

Introduction

In Rust, Receiver is a type used to receive messages from a channel. It is part of the standard library's std::sync::mpsc module, where mpsc stands for "multiple producer, single consumer." Channels provide a way for different parts of your code to communicate with each other, especially in concurrent programming. The Receiver is used to read messages sent by the corresponding Sender.

Using Receiver

To use Receiver, you need to create a channel using the std::sync::mpsc::channel function, which returns a (Sender, Receiver) pair. You can then use the Receiver to receive messages sent through the channel.

use std::sync::mpsc;
use std::thread;
use std::time::Duration;

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

    thread::spawn(move || {
        tx.send("Hello from the spawned thread!").unwrap();
    });

    let received = rx.recv().unwrap();
    println!("Received: {}", received);
}
// Output:
// Received: Hello from the spawned thread!

Key Methods

Below are some of the key methods exposed by the Receiver class:

recv

Blocks the current thread until a message is available and returns it. If the channel is closed, it returns an Err.

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

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

    thread::spawn(move || {
        tx.send(42).unwrap();
    });

    let received = rx.recv().unwrap();
    println!("Received: {}", received);
}
// Output:
// Received: 42

try_recv

Tries to receive a message from the channel without blocking. It returns immediately with a Result, which is Ok(T) if a message is available, or Err(TryRecvError) if the channel is empty or closed.

use std::sync::mpsc;
use std::thread;
use std::time::Duration;

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

    thread::spawn(move || {
        tx.send(42).unwrap();
    });

    thread::sleep(Duration::from_millis(100));

    match rx.try_recv() {
        Ok(received) => println!("Received: {}", received),
        Err(e) => println!("Failed to receive: {:?}", e),
    }
}
// Output:
// Received: 42

iter

Returns an iterator that will yield messages received from the channel. The iterator ends when the channel is closed and all messages have been received.

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

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

    thread::spawn(move || {
        for i in 0..5 {
            tx.send(i).unwrap();
        }
    });

    for received in rx.iter() {
        println!("Received: {}", received);
    }
}
// Output:
// Received: 0
// Received: 1
// Received: 2
// Received: 3
// Received: 4

Example Usage

Example 1: Basic Usage

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

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

    thread::spawn(move || {
        tx.send("Hello from the spawned thread!").unwrap();
    });

    let received = rx.recv().unwrap();
    println!("Received: {}", received);
}
// Output:
// Received: Hello from the spawned thread!

Example 2: Receiving Multiple Messages

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

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

    thread::spawn(move || {
        tx.send(1).unwrap();
        tx.send(2).unwrap();
        tx.send(3).unwrap();
    });

    for _ in 0..3 {
        let received = rx.recv().unwrap();
        println!("Received: {}", received);
    }
}
// Output:
// Received: 1
// Received: 2
// Received: 3

Example 3: Non-blocking Receive

use std::sync::mpsc;
use std::thread;
use std::time::Duration;

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

    thread::spawn(move || {
        thread::sleep(Duration::from_millis(50));
        tx.send(42).unwrap();
    });

    match rx.try_recv() {
        Ok(received) => println!("Received: {}", received),
        Err(e) => println!("Failed to receive: {:?}", e),
    }

    thread::sleep(Duration::from_millis(100));

    match rx.try_recv() {
        Ok(received) => println!("Received: {}", received),
        Err(e) => println!("Failed to receive: {:?}", e),
    }
}
// Output:
// Failed to receive: Empty
// Received: 42

Example 4: Iterating Over Messages

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

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

    thread::spawn(move || {
        for i in 0..5 {
            tx.send(i).unwrap();
        }
    });

    for received in rx.iter() {
        println!("Received: {}", received);
    }
}
// Output:
// Received: 0
// Received: 1
// Received: 2
// Received: 3
// Received: 4

Example 5: Handling Channel Closure

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

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

    thread::spawn(move || {
        tx.send(1).unwrap();
        // Dropping the sender to close the channel
        drop(tx);
    });

    loop {
        match rx.recv() {
            Ok(received) => println!("Received: {}", received),
            Err(_) => {
                println!("Channel closed");
                break;
            }
        }
    }
}
// Output:
// Received: 1
// Channel closed

Considerations

  • Channels provide a powerful way to communicate between threads, but they can introduce complexity and potential for deadlocks if not managed carefully.
  • Always handle the Result returned by recv and try_recv to manage possible errors when the channel is closed.
  • Dropping the Sender will close the channel, causing recv to return an error once all messages have been received.

See Also

  • Sender - The sending half of a channel used to send messages.
  • JoinHandle - A handle for managing the lifecycle of a thread.
  • Mutex - A mutual exclusion primitive for protecting shared data.