Receiver în Rust

Capătul de primire al unui canal mpsc: recv() așteaptă următorul mesaj, try_recv() verifică fără să aștepte.

Sintaxă
fn recv(&self) -> Result<T, RecvError>
fn try_recv(&self) -> Result<T, TryRecvError>

Ce face Receiver

recv() blochează firul până sosește un mesaj și returnează Ok(mesaj). Dacă nu mai există niciun Sender și canalul este gol, returnează Err(RecvError), semn că nu vor mai veni mesaje.

try_recv() nu așteaptă: returnează imediat Ok(mesaj) dacă există unul, Err(TryRecvError::Empty) dacă acum nu e nimic sau Err(TryRecvError::Disconnected) dacă toți expeditorii au dispărut. Este util într-o buclă care face și altă treabă între verificări.

Un Receiver poate fi parcurs și cu for mesaj in rx (sau rx.iter()): bucla apelează recv() și se oprește când canalul se închide. Mai există recv_timeout(durata).

Ce returnează

recv: Result<T, RecvError>. try_recv: Result<T, TryRecvError>.

Exemple

Exemplul 1: recv până se închide canalul

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

fn main() {
    let (tx, rx) = mpsc::channel();
    let fir = thread::spawn(move || {
        for nota in [9, 7, 10] {
            tx.send(nota).unwrap();
        }
    });

    let mut suma = 0;
    loop {
        match rx.recv() {
            Ok(nota) => {
                println!("am primit nota {nota}");
                suma += nota;
            }
            Err(e) => {
                println!("canal închis ({e})");
                break;
            }
        }
    }
    fir.join().unwrap();
    println!("suma: {suma}");
}

Rezultat

am primit nota 9
am primit nota 7
am primit nota 10
canal închis (receiving on a closed channel)
suma: 26

Exemplul 2: try_recv: Empty, mesaj, Disconnected

Totul se întâmplă în același fir, deci ordinea este fixă: întâi canalul e gol, apoi are un mesaj, apoi se închide.

use std::sync::mpsc;

fn main() {
    let (tx, rx) = mpsc::channel::<&str>();

    println!("1: {:?}", rx.try_recv());
    tx.send("comandă nouă").unwrap();
    println!("2: {:?}", rx.try_recv());
    println!("3: {:?}", rx.try_recv());
    drop(tx);
    println!("4: {:?}", rx.try_recv());
    println!("recv după închidere: {:?}", rx.recv());
}

Rezultat

1: Err(Empty)
2: Ok("comandă nouă")
3: Err(Empty)
4: Err(Disconnected)
recv după închidere: Err(RecvError)

Greșeli frecvente

  • Apelezi recv() în bucla principală a unei aplicații care trebuie să facă și altceva: firul stă blocat. Folosește try_recv sau recv_timeout.
  • Încerci să clonezi Receiver-ul pentru mai multe fire: nu se poate. Pentru mai mulți consumatori, pune-l într-un Arc<Mutex<Receiver<T>>>.

Comenzi înrudite

  • mpsc::channel: Creează un canal prin care firele își trimit mesaje: Sender trimite cu send(), Receiver primește.
  • thread::spawn: Pornește un fir de execuție nou care rulează funcția dată; join() așteaptă terminarea lui și îi dă rezultatul.
  • Duration: O durată de timp (secunde și nanosecunde), creată cu from_secs, from_millis; se poate aduna, înmulți și compara.