我正在通过某种发布者/订阅者模型通过某个链接与某些硬件进行对话。在C ++中,我使用RAII进行订阅以记住总是取消订阅,但是我似乎无法完全摆脱所有权/借款。
天真的,这就像我想做的一样。 send
和receive
可能需要为&mut self
,据我所知,Subscription
需要对Transport
的可变访问。
struct Transport;
impl Transport {
pub fn send(&mut self, cmd: &str) { unimplemented!() }
pub fn subscribe(&mut self, cmd: &str) -> Subscription {
self.send("subscribe-with-params");
Subscription { trans: &mut self }
}
}
struct Subscription {
trans: &mut Transport,
}
impl Drop for Subscription {
fn drop(&mut self) {
self.trans.send("unsubscribe-with params");
}
}
impl Subscription {
fn receive(&mut self) -> &[u8] { /*blocking wait for data*/ }
}
fn test(t: Transport) {
// Need to subscribe before command, as command might generate status messages
let mut status_sub = t.subscribe("status-message");
{
let mut short_lived_sub = t.subscribe("command_reply");
t.send("command");
short_lived_sub.receive(); // Wait for ack
}
loop {
println!("{:?}", status_sub.receive());
/*processing of status */
}
}
这里至少有两个问题。一种是Subscription
应该如何引用其“父母” Transport
,另一种是fn test
中的问题,我不能两次借用Transport
不同的订阅。
我觉得我在这里问错了一个问题,所以也许有一种完全不同的方式来解决这个问题的好方法?
答案 0 :(得分:2)
您的Subscription
持有对Transport
的可变引用是有问题的,因为,正如您所发现的,您一次只能持有一个,而您将无法在此期间,还要对运输进行其他任何操作。
相反,您可以使用Rc
(用于共享所有权)和RefCell
(用于内部可变性):
use std::rc::Rc;
use std::cell::RefCell;
struct TransportInner;
pub struct Transport {
inner: Rc<RefCell<TransportInner>>,
}
pub struct Subscription {
trans: Rc<RefCell<TransportInner>>
}
impl TransportInner {
pub fn send(&mut self, cmd: &str) { }
}
impl Transport {
pub fn send(&mut self, cmd: &str) {
self.inner.borrow_mut().send(cmd)
}
pub fn subscribe(&mut self, cmd: &str) -> Subscription {
self.send("subscribe-with-params");
Subscription { trans: Rc::clone(&self.inner) }
}
}
impl Drop for Subscription {
fn drop(&mut self) {
self.trans.borrow_mut().send("unsubscribe-with params");
}
}
您可以执行此操作而无需将其拆分为内部和外部结构,但这将要求用户也通过Transport
访问Rc
,这可能很麻烦。
如果您需要跨线程工作,则应改用Arc<Mutex>
。