如何使用 RAII 属性创建订阅者对象?
Posted
技术标签:
【中文标题】如何使用 RAII 属性创建订阅者对象?【英文标题】:How to make a subscriber object with RAII properties? 【发布时间】:2019-06-27 12:33:01 【问题描述】:我正在与一些硬件通过发布者/订阅者模型的链接进行交谈。在 C++ 中,我使用 RAII 进行订阅以记住始终取消订阅,但我似乎无法在 rust 中获得所有权/借用权。
天真地,这就是我想做的事情。 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
。
我觉得我在这里问了一个错误的问题,所以也许有一种完全不同的方式来解决这个问题的好方法?
【问题讨论】:
【参考方案1】:您的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");
您可以在不将其拆分为内部结构和外部结构的情况下执行此操作,但这需要用户也通过Rc
访问Transport
,这可能很笨拙。
如果您需要它跨线程工作,您应该改用Arc<Mutex>
。
【讨论】:
以上是关于如何使用 RAII 属性创建订阅者对象?的主要内容,如果未能解决你的问题,请参考以下文章
如何通过另一个可观察对象观察已发布的属性 - Swift Combine