我想用自己的结构和函数包装一个低级的第三方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
的包装?
答案 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
}
}
我注意到完成这项工作的两件重要事情:
low
结构中Wrapper
上的生命周期名称必须与“拥有”字段的名称(在本例中为“ 'stream
”)匹配new()
中,第二个参数不是LowLevelApi
,它是一个闭包,它获取&mut TcpStream
,然后期望该闭包返回一个LowLevelApi
LowLevelApi
时,您可以对其进行“租赁”,因此wrapper.rent_mut(f)
其中f
是通过{ {1}}(LowLevelApi
)并可以做所需的事有了这些事实,Rental文档的其余部分就更加有意义了。