I use an mpsc channel to create N (known at runtime) tasks sending messages to one receiver; see Playground & code below.
Because I create the N tasks dynamically, I clone tx1 for each of them. In the end, I am therefore in possession of N+1 Sender references, N of which will get used for message-passing and eventually drop out-of-scope. Sadly, I am left with the original tx1 reference that was used to clone the other ones. But to get a well-behaved channel for which recv() returns None at the end, all Senders need to eventually drop. I therefore invoke drop(tx1).
While it looks perfectly fine to do so, it feels wrong and slightly ugly. Could you suggest better-looking code that does not involve eg. special-casing the first or last iteration of the task creation? Or is this The Right Way™?
use std::sync::mpsc::channel;
use std::thread::spawn;
fn main() {
let (tx1, rx) = channel();
(0..10).for_each(|i| {
let tx = tx1.clone();
spawn(move || { tx.send(Some(i)).unwrap(); });
});
// How can I make this not necessary?
drop(tx1);
for i in rx.iter() {
println!("received {:?}", i);
}
println!("done!");
}
use std::sync::mpsc::channel;
use std::thread::spawn;
use std::iter;
fn main() {
let (tx, rx) = channel();
for (i, tx) in iter::repeat(tx).take(10).enumerate() {
spawn(move || { tx.send(Some(i)).unwrap(); });
}
for i in rx {
println!("received {:?}", i);
}
println!("done!");
}
These solutions are definitely cleaner, but note they'll essentially end up doing the same thing (cloning 10 times and then dropping the original). If you need to avoid this for some reason, you can use itertools::repeat_n.