同时改变多个结构字段的最快惯用方法是什么?

What's the fastest idiomatic way to mutate multiple struct fields at the same time?

许多库允许您定义实现给定 trait 的类型以用作回调处理程序。这要求您将处理事件所需的所有数据集中在一个数据类型中,这会使借用变得复杂。

例如,mio allows you to implement Handler and provide your struct when you run the EventLoop。考虑一个具有这些简单数据类型的示例:

struct A {
  pub b: Option<B>
};

struct B;

struct MyHandlerType {
  pub map: BTreeMap<Token, A>,
  pub pool: Pool<B>
}

您的处理程序具有从 Token 到类型 A 的项目的映射。 A 类型的每个项目可能已经或可能没有关联的 B 类型的值。在处理程序中,您想查找给定 TokenA 值,如果它还没有 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.mapself.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 的开销。

最好的方法是什么?

要同时获取对结构不同部分的可变引用,请使用解构。示例 here.

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());
}