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?