包装一个借来东西的结构

时间:2019-10-10 02:02:29

标签: rust

我想用自己的结构和函数包装一个低级的第三方API,以使其更加友好。不幸的是,第三方API需要在其构造函数中引用套接字,这意味着我希望我的Struct“拥有”该套接字(有人必须拥有它才能借用它,对吗?就像隐藏在我的API中的实现细节一样。

第三方API看起来像这样:

struct LowLevelApi<'a> {
    stream: &'a mut TcpStream,
    // ...
}

impl<'a> LowLevelApi<'a> {
    pub fn new(socket: &'a mut TcpStream, ... ) -> LowLevelApi<'a> {
        // ...
    }
}

我想使函数接口看起来像这样:

pub fn new(host: String, port: u16, ...) -> HighLevelApi {
    // ...
}

我尝试过:

pub struct HighLevelApi<'a> {
    stream: TcpStream,
    low: LowLevelApi<'a>
}

impl <'a> HighLevelApi<'a> {
    pub fn new(host: String, port: u16) -> HighLevelApi<'a> {
        // Ignore lack of error checking for now
        let mut stream = TcpStream::connect(format!("{}:{}", host, port)).unwrap();
        HighLevelApi {
            stream,
            low: LowLevelApi::new(&mut stream)
        }
    }
}

Rust(正确地)很生气:它无法得知我以后不会对low字段做任何不好的事情。甚至更糟的是,我需要以某种方式保证当我的结构被删除时,low首先被删除,而stream之后被删除(因为那时,两者之间的任何关系都丢失了,或者,两者之间从来没有/没有关系。

(实际上,这比那更糟,因为stream局部变量被移到新结构中,所以LowLevelApi不可能借用该局部变量,但是我想不到一种从结构体中使用HighLevelApi初始化stream的方法,因为没有办法从结构体的初始化中获取该句柄,是吗?但是基于我的猜测,上面的段落并不重要,因为它仍然无法满足我的要求。

哪些技术可用于存储需要引用某些内容的第三方(不受我控制)struct的包装?

1 个答案:

答案 0 :(得分:0)

Rental板条箱似乎可以满足此处的要求,尽管文档和示例让人难以想象(例如反复试验)。

以下是解决此问题的大致原因

rental! {
    pub mod rentals {
        #[rental_mut]
        pub struct Wrapper {
            stream: Box<TcpStream>,
            low: LowLevelApi<'stream>
        }
    }
}

pub struct HighLevelApi {
    wrapper: rentals::Wrapper
}

impl HighLevelApi {
    pub fn new(host: String, port: u16) -> HighLevelApi {
        Api {
            // Ignore lack of error checking for now
            wrapper: rentals::Wrapper::new(
                Box::new(TcpStream::connect(format!("{}:{}", host, port)).unwrap()),
                |s| LowLevelApi::new(s)
            )
        }
    }

    pub fn do_something(&mut self) {
        self.wrapper.rent_mut(|ll| ll.do_something()) // ll is the LowLevelApi
    }
}

我注意到完成这项工作的两件重要事情:

  1. low结构中Wrapper上的生命周期名称必须与“拥有”字段的名称(在本例中为“ 'stream”)匹配
  2. 您永远无法直接访问引用-通过回调/关闭获取它:
    1. 在自动生成的构造函数(new()中,第二个参数不是LowLevelApi,它是一个闭包,它获取&mut TcpStream,然后期望该闭包返回一个LowLevelApi
    2. 当您想真正使用 LowLevelApi时,您可以对其进行“租赁”,因此wrapper.rent_mut(f)其中f是通过{ {1}}(LowLevelApi)并可以做所需的事

有了这些事实,Rental文档的其余部分就更加有意义了。