How do I use a Tokio oneshot sender and receiver on different tasks with inner loops?

Viewed 2688

Not sure how to handler the borrow checker here.

use tokio::sync::oneshot; // 1.0.2

fn main() {
    let (sender, receiver) = oneshot::channel::<u8>();
    tokio::spawn(async move {
        loop {
            sender.send(3).unwrap();
        }
    });
}

Creates this error:

error[E0382]: use of moved value: `sender`
 --> src/main.rs:7:13
  |
7 |             sender.send(3).unwrap();
  |             ^^^^^^ value moved here, in previous iteration of loop
  |
  = note: move occurs because `sender` has type `tokio::sync::oneshot::Sender<u8>`, which does not implement the `Copy` trait
1 Answers

You don't. That's the entire point of a oneshot channel: it can only be used a maximum of one time:

A channel for sending a single message between asynchronous tasks.

— tokio::sync::oneshot

It sounds like you want a different kind of channel, such as tokio::sync::mpsc.


what if I only want to send one message at the start of the loop?

Then perform the code before the loop starts:

use tokio::sync::oneshot; // 1.0.2

fn main() {
    let (sender, receiver) = oneshot::channel::<u8>();
    tokio::spawn(async move {
        sender.send(3).unwrap();
        
        loop {
            // Do things
        }
    });
}

If you had to have it inside the loop, you need to dynamically mark the value as no longer there and handle that case. Here, I use an Option and if let:

use tokio::sync::oneshot; // 1.0.2

fn main() {
    let (sender, receiver) = oneshot::channel::<u8>();
    tokio::spawn(async move {
        let mut sender = Some(sender);
        
        loop {
            if let Some(sender) = sender.take() {
                sender.send(3).unwrap();
            }
            // Do things
        }
    });
}
Related