Какой самый быстрый идиоматический способ изменить несколько структурных полей одновременно?

Многие библиотеки позволяют вам определять тип, который реализует данный 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());
}
Другие вопросы по тегам