Reputation: 623
I've narrowed this as much as I can. I have a vector of references to Senders
and want to process them after receive()
has completed running. However I'm running into a lifetime management issue. The inner struct is Mutex
protected and contains the Senders
that I'm trying to reference. I use the Mutex to gain mutability of the data, I'm open to alternatives. Any suggestions on how to work around this? I'd prefer not to change the signature of receive().
use std::sync::Mutex;
use std::sync::mpsc;
#[derive(Default)]
struct SaveForLater<'a> {
queue: Vec<(&'a mpsc::Sender<usize>, usize)>,
}
impl<'a> SaveForLater<'a> {
fn send(&mut self, channel: &'a mpsc::Sender<usize>, value: usize) {
self.queue.push((channel, value));
}
}
#[derive(Default)]
struct Forwarder {
data: Mutex<ForwarderData>,
}
#[derive(Default)]
struct ForwarderData {
senders: Vec<mpsc::Sender<usize>>,
}
impl Forwarder {
fn with_capacity(capacity: usize) -> Self {
let mut senders = Vec::new();
for _ in 0..capacity {
let (s,r) = mpsc::channel();
senders.push(s);
}
let data = ForwarderData { senders };
let data = Mutex::new(data);
Self { data }
}
fn receive<'a>(&'a self, value: usize, sender: &mut SaveForLater<'a>) {
match value {
0 => { self.data.lock().unwrap().senders.drain(..); },
_ => {
let data = self.data.lock().unwrap();
sender.send(&data.senders[0], value); },
/*
error[E0597]: `data` does not live long enough
--> src/main.rs:40:30
|
35 | fn receive<'a>(&'a self, value: usize, sender: &mut SaveForLater<'a>) {
| -- lifetime `'a` defined here
...
40 | sender.send(&data.senders[0], value); },
| -------------^^^^------------------- - `data` dropped here while still borrowed
| | |
| | borrowed value does not live long enough
| argument requires that `data` is borrowed for `'a`
*/
}
}
}
fn main() {
let fwd = Forwarder::with_capacity(3);
{
let mut sender = SaveForLater::default();
let value: usize = 42;
fwd.receive(value, &mut sender);
for (s,v) in sender.queue {
s.send(v);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_main() {
main();
}
}
see error in playground
Upvotes: 1
Views: 204
Reputation: 27885
Mutex
is a distraction here; the real problem is trying to store references in structs. Let's look at the documentation of mpsc::Sender
to see how it's supposed to be used:
The sending-half of Rust's asynchronous
channel
type. This half can only be owned by one thread, but it can be cloned to send to other threads.
Sender
does not even implement Sync
, so even if you make the borrow checker happy you won't be able to share a single one between multiple threads. It's meant to be cloned instead:
struct SaveForLater {
queue: Vec<(mpsc::Sender<usize>, usize)>,
}
fn receive(&self, value: usize, sender: &mut SaveForLater) {
// ...
sender.send(data.senders[0].clone(), value);
// ^^^^^^^^
Here's a full example. No lifetime parameters are necessary.
In general you should avoid putting references in structs because it can only be done safely if you are very diligent about proving the lifetime relationships at compile time. In most cases you should simply clone the data, or if that's the wrong semantic, use Arc
or Rc
. mpsc::Sender
uses Arc
internally to be cheap to clone.
Upvotes: 1