2016-09-22 4 views
1

Я сражаюсь с последним боссом ржавчины, проверкой займа. Это упрощенная версия приложения с реактивной сетью mio, над которым я работаю. Я потратил слишком много времени на поиск правильной структуры данных для задачи. Я хочу зарегистрировать соединение во время итерации через сокеты прослушивания, которые могут принимать новые соединения.Как найти структуру без наложения изображений

См. Следующий код или на нем Rust playground. HashMap::get_mut возвращает уникальный заем до 1 значения в 1 поле self, поэтому я не могу перейти на self в Thing::act. Я понимаю, почему это происходит, как это вызывает проблему во время выполнения, но не имеет понятия, как реорганизовать структуру данных, чтобы избежать таких проблем.

use std::collections::HashMap; 

trait ThingSet { 
    fn register(&mut self, thing: Box<Thing>); 
} 

trait Thing { 
    fn act(&mut self, reg: &mut ThingSet); 
} 

struct Stream; 

impl Thing for Stream { 
    fn act(&mut self, reg: &mut ThingSet) {} 
} 

struct Listener; 

impl Thing for Listener { 
    fn act(&mut self, reg: &mut ThingSet) { 
     if true { 
      let mut stream = Stream {}; 
      reg.register(Box::new(stream)); 
     } 
    } 
} 

struct Loop { 
    next: usize, 
    things: HashMap<usize, Box<Thing>>, 
} 

impl Loop { 
    fn new() -> Loop { 
     Loop { next: 1, things: HashMap::new(), } 
    } 
    fn run(&mut self) { 
     let mut needs_action = Vec::<&mut Box<Thing>>::new(); 
     { 
      // modeling a connection on one of the listeners... 
      if let Some(t) = self.things.get_mut(&1usize) { 
       needs_action.push(t); 
      } 
     } 
     for t in needs_action { 
      t.act(self as &mut ThingSet); 
     } 
    } 
} 

impl ThingSet for Loop { 
    fn register(&mut self, thing: Box<Thing>) { 
     self.things.insert(self.next, thing); 
     self.next += 1; 
    } 
} 

fn main() { 
    let mut l = Loop::new(); 
    let mut p1 = Listener {}; 
    let mut p2 = Listener {}; 
    l.register(Box::new(p1)); 
    l.register(Box::new(p2)); 
    l.run(); 
} 

я мог бы найти хорошие учебники, объясняющие, что заимствуют проверки делает и то, что не разрешено ею. Я не мог найти хорошие учебные пособия о том, как найти альтернативные структуры данных, где я могу избежать запрещенных ссылок.

Не могли бы вы дать рекомендации о том, как переделать эту конкретную проблему?

+0

По какой-то причине @Jsor удален свой пост, но у него было 2 хороших гов в нем: https: // play.rust-lang.org/?gist=710aefc653b320c653f289f5e3eee972 и https://play.rust-lang.org/?gist=4fecb8d2b584252fd6b6e687db34de5a – wigy

+0

Я отвечу ответ @ breeden перед уикэндом, если кто-то не придумает структуру данных, которая позволяет статично заимствовать проверку для этого прецедента. – wigy

+0

Я удалил его, потому что в небезопасном решении он приводит к использованию после освобождения, если вы удалите запись в 'needs_action' из' act' другого слушателя. Кроме того, ее – LinearZoetrope

ответ

2

Я думаю, что можно исправить эту конкретную проблему, но я чувствую, что здесь может быть более общая проблема. Исправьте меня, если я ошибаюсь, но кажется, что вы запустили Loop::run, он будет сканировать через ваш ThingSet, а затем каким-то условием поместите измененную ссылку на Thing на буфер needs_action. Общий вывод здесь кажется, что через разные итерации rustc не может проверить, что эти разные вызовы предоставят вам другую изменяемую ссылку или другую изменяемую ссылку на тот же элемент. Таким образом, вы можете обеспечить проверку заимствования во время выполнения, используя что-то вроде RefCell (см. Ответ Jsor), или вы можете получить право собственности от своего ThingSet и заменить то, что вы сделали с чем-то другим, или удалить элемент из набора вместе ,

Например, берут на себя ответственность элемента и удаление его из ThingSet показано здесь:

impl Loop { 
    fn new() -> Loop { 
     Loop { next: 1, things: HashMap::new(), } 
    } 
    fn run(&mut self) { 
     let mut needs_action = Vec::<Box<Thing>>::new(); 

     // modeling a connection on one of the listeners... 
     if let Some(t) = self.things.remove(&1usize) { 
      needs_action.push(t); 
     } 

     for t in &mut needs_action { 
      t.act(self as &mut ThingSet); 
     } 
    } 
} 
+0

Это вариант, но я думаю вместо «заменить» лучше использовать 'remove' из' HashMap' и при необходимости вставить его. – LinearZoetrope

+0

Я, наверное, должен это изменить. – breeden

+1

ОК, поэтому идея состоит в том, что статический анализ невозможен с этой структурой данных, поэтому 'Rc >' обеспечит такую ​​же безопасность, используя проверки времени выполнения. – wigy