如何使用 RAII 属性创建订阅者对象?

Posted

技术标签:

【中文标题】如何使用 RAII 属性创建订阅者对象?【英文标题】:How to make a subscriber object with RAII properties? 【发布时间】:2019-06-27 12:33:01 【问题描述】:

我正在与一些硬件通过发布者/订阅者模型的链接进行交谈。在 C++ 中,我使用 RAII 进行订阅以记住始终取消订阅,但我似乎无法在 rust 中获得所有权/借用权。

天真地,这就是我想做的事情。 sendreceive 可能需要为 &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&lt;Mutex&gt;

【讨论】:

以上是关于如何使用 RAII 属性创建订阅者对象?的主要内容,如果未能解决你的问题,请参考以下文章

如何创建 CloudKit 订阅通知以触发记录属性更新?

如何使用 RAII 对套接字进行建模

如何通过另一个可观察对象观察已发布的属性 - Swift Combine

如何通过 terraform 使用服务帐户创建 google cloud pubsub pull 订阅?

如何获取 Azure 主题订阅的消息计数?

使用智能指针来管理对象 (基于RAII)