6

许多库允许您定义一个实现给定的类型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.mapself.pool

一种可能的方法是将每个字段包装MyHandlerTypeOption<>. 然后,在方法调用开始时,将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为每个方法调用引入了将值移入和移出的开销。

最好的方法是什么?

4

1 回答 1

14

要同时获取对结构不同部分的可变引用,请使用解构。这里的例子。

struct Pair {
    x: Vec<u32>,
    y: Vec<u32>,
}

impl Pair {
    fn test(&mut self) -> usize {
        let Pair{ ref mut x, ref mut y } = *self;
        // Both references coexist now
        return x.len() + y.len();
    }
}

fn main() {
    let mut nums = Pair {
        x: vec![1, 2, 3],
        y: vec![4, 5, 6, 7],
    };
    println!("{}", nums.test());
}
于 2015-09-04T18:39:25.973 回答