2017-09-03 17 views
1

チップ8エミュレータを作成しようとしていますが、ボローチェッカーが苦労しています。メソッドポインタをHashMapに格納して呼び出す方法

アイデアはHashMap内のメソッドポインタを検索し、このメソッドポインタを実行してオペコードをデコードすることですが、私は正常に動作するように変更可能なメソッドのポインタを取得することはできません:ポインタを使用して

struct Chip8 { 
    opcode: u16, 
    //... other fields 
    jump_table: HashMap<u16, Box<fn(&mut Chip8)>>, 
} 

の機能:

fn execute_decoded(&mut self, key: u16) { 
    let func = self.jump_table.get(&key); 

    match func { 
     Some(func) => func(self), 
     None => { 
      println!("invalid op: {}", self.opcode); 
      sleep(Duration::from_millis(10000)); 
      return; 
     } 
    }(); 

    self.program_counter = self.program_counter + 2; 
} 

チェッカーは文句:

cannot borrow `*self` as mutable because `self.jump_table` is also borrowed as immutable 
    --> main.rs:168:36 
    | 
165 |    let func = self.jump_table.get(&key); 
    |      --------------- immutable borrow occurs here 
... 
168 |     Some(func) => func(self), 
    |         ^^^^ mutable borrow occurs here 
... 
178 |  } 
    |  - immutable borrow ends here 

このエラーがなぜ起こっているのか分かりません。

self.jump_table.get(&key)はなぜ借りるのですか? execute_decodedの署名に基づいて、私はそれがselfの変更可能な借用バージョンで動作し、追加の借用は必要ないと仮定していました。

答えて

2

HashMapは、その中のすべてを所有しています。あなたの関数ポインタを取得するには、let func = self.jump_table.get(&key);でそれを借りています。だから、funcであり、借り換え不可能なものはself.jump_table(これはselfの要素です)です。

selfのすべてをfuncに渡そうとしています。あなたがselfをあなたが望む数だけ不変に借りることができるので、selfを不変に渡すなら、これはうまくいくでしょう。しかし、selfを可変的に借りようとしているので、部分self(特にself.jump_table)を不変に借りているので、コンパイラはこれを許可しません。

Chip8構造体をより小さい構造体に分割することで、も渡さずに、すべての必要な情報をfuncに渡すことができます。

+1

、コンパイラは 'func'は、などによって変更*それが無効になるように' self'、*しないという保証はありませんハッシュマップをクリアします。 – Shepmaster

4

Boxには、HashMapの関数ポインタがあり、不要な間接参照しか導入されません。

already been mentionedと同様に、関数ポインタを借りています。事は、理由がないということです。あなただけHashMapから関連付けを解除する関数ポインタをコピーすることができます。

考えを完了
use std::collections::HashMap; 

struct Chip8 { 
    jump_table: HashMap<u16, fn(&mut Chip8)>, 
} 

impl Chip8 { 
    fn execute_decoded(&mut self, key: u16) { 
     let func = self.jump_table.get(&key).map(|x| *x); 

     match func { 
      Some(func) => func(self), 
      None => { 
       println!("invalid op"); 
      } 
     }; 
    } 
} 

fn main() {} 
関連する問題