许多库允许您定义一个实现给定的类型trait
以用作回调处理程序。这要求您将处理事件所需的所有数据集中在一个数据类型中,这使借用变得复杂。
例如,mio
允许您Handler
在运行EventLoop
. 考虑一个具有这些平凡数据类型的示例:
struct A {
pub b: Option<B>
};
struct B;
struct MyHandlerType {
pub map: BTreeMap<Token, A>,
pub pool: Pool<B>
}
Token
您的处理程序有一个从到类型的项目的映射A
。每个 type 项A
可能已经或可能没有 type 的关联值B
。在处理程序中,您想要查找A
给定的值Token
,如果它还没有B
值,请从处理程序的Pool<B>
.
impl Handler for MyHandlerType {
fn ready(&mut self, event_loop: &mut EventLoop<MyHandlerType>,
token: Token, events: EventSet) {
let a : &mut A = self.map.get_mut(token).unwrap();
let b : B = a.b.take().or_else(|| self.pool.new()).unwrap();
// Continue working with `a` and `b`
// ...
}
}
在这种安排中,即使直观地可以看到它self.map
是不同的实体,但借用检查器会在我们访问时self.pool
抱怨self
已经借用(通过) 。self.map
self.pool
一种可能的方法是将每个字段包装MyHandlerType
在Option<>
. 然后,在方法调用开始时,将take()
这些值取出self
并在调用结束时恢复它们:
struct MyHandlerType {
// Wrap these fields in `Option`
pub map: Option<BTreeMap<Token, A>>,
pub pool: Option<Pool<B>>
}
// ...
fn ready(&mut self, event_loop: &mut EventLoop<MyHandlerType>,
token: Token, events: EventSet) {
// Move these values out of `self`
let map = self.map.take().unwrap();
let pool = self.pool.take().unwrap();
let a : &mut A = self.map.get_mut(token).unwrap();
let b : B = a.b.take().or_else(|| self.pool.new()).unwrap();
// Continue working with `a` and `b`
// ...
// Restore these values to `self`
self.map = Some(map);
self.pool = Some(pool);
}
这行得通,但感觉有点笨拙。它还self
为每个方法调用引入了将值移入和移出的开销。
最好的方法是什么?