2016-09-22 6 views
1

私は借りたチェッカーであるRustの最終的なボスと戦っています。これは私が取り組んでいるmio反応ネットワークアプリケーションの簡略化されたバージョンです。私はあまりにも多くの時間を費やして、手元にあるタスクの正しいデータ構造を見つけ出しました。新しい接続を受け入れることができるリスニングソケットを反復しながら接続を登録したいと思います。エイリアシングフリーのデータ構造を見つける方法

次のコードを参照するか、Rust playgroundで確認してください。 HashMap::get_mutは、selfの1フィールドに1の値に一意のボローを返します。したがって、selfThing::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

をplay.rust-lang.org/?gist=710aefc653b320c653f289f5e3eee972とhttps://play.rust-lang.org/?gist=4fecb8d2b584252fd6b6e687db34de5a – wigy

+0

週末の前に@ breedenの回答を受け入れる人がいます。誰かが静的このユースケースのチェックを借りてください。 – wigy

+0

安全な解決策では、 'needs_action'のエントリを別のリスナーの' act'から削除すると、use-after-freeという結果になるので、削除しました。また、彼女の – LinearZoetrope

答えて

2

この特定の問題を修正することは可能だと思いますが、ここではもっと一般的な懸念があるかもしれません。私が間違っている場合は私を訂正しますが、Loop::runを実行すると、ThingSetをスキャンし、ある状況ではThingへの変更可能な参照をneeds_actionバッファに入れます。 一般的なの問題は、異なる繰り返しによって、rustcはこれらの異なる呼び出しが同じ要素に対する別の変更可能な参照または別の変更可能な参照を与えることを検証できないようです。したがって、RefCell(Jsorの答えを参照)のようなものを使用して実行時の借り入れチェックを実施することも、ThingSetから所有権を取得して、何か他のものに置き換えることもできます。 。例えば

、要素の所有権を取得し、ThingSetからそれを削除すると、ここに例示されてます。https:// @Jsorは彼のポストを削除したが、彼はそれで2つの良い要旨を持っていたいくつかの理由

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

これはオプションですが、 'replace'の代わりに' HashMap'から 'remove'を使い、必要ならばそれを再挿入する方が良いと思います。 – LinearZoetrope

+0

ええ、私はおそらくそれを変更する必要があります。 – breeden

+1

これは、このデータ構造では静的解析が不可能であるため、 'Rc >'はランタイムチェックを使用して同じ安全性を提供します。 – wigy

関連する問題