Qual é a maneira idiomática mais rápida de alterar vários campos struct ao mesmo tempo?

Muitas bibliotecas permitem definir um tipo que implementa um determinadotrait para ser usado como manipulador de retorno de chamada. Isso exige que você agrupe todos os dados necessários para manipular o evento juntos em um único tipo de dados, o que complica os empréstimos.

Por exemplo,mio permite implementarHandler e forneça sua estrutura quando vocêexecute oEventLoop. Considere um exemplo com estes tipos de dados trivializados:

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

struct B;

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

Seu manipulador tem um mapa deToken para itens do tipoA. Cada item do tipoA pode ou não ter um valor associado do tipoB. No manipulador, você deseja procurar oA valor para um dadoToken e, se ainda não tiver umB valor, tire um do manipuladorPool<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`
       // ...
    }
}

Nesse arranjo, mesmo que seja intuitivamente possível ver queself.map eself.pool são entidades distintas, o verificador de empréstimos reclama queself já está emprestado (viaself.map) quando vamos acessarself.pool.

Uma abordagem possível para isso seria agrupar cada campo emMyHandlerType noOption<>. Em seguida, no início da chamada do método,take() esses valores foraself e restaure-os no final da chamada:

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

Isso funciona, mas parece um pouco confuso. Ele também introduz a sobrecarga de mover valores dentro e fora deself para cada chamada de método.

Qual é a melhor forma de fazer isso?

questionAnswers(1)

yourAnswerToTheQuestion