Какой самый быстрый идиоматический способ изменить несколько структурных полей одновременно?
Многие библиотеки позволяют вам определять тип, который реализует данный 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
, Каждый элемент типа A
может или не может уже иметь ассоциированное значение типа 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);
}
Это работает, но чувствует себя немного kluge-у. Он также вводит накладные расходы на перемещение значений в и из self
для каждого вызова метода.
Какой лучший способ сделать это?
1 ответ
Чтобы получить одновременно изменяемые ссылки на различные части структуры, используйте деструктуризацию. Пример тут.
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());
}