2017-09-03 3 views
1

Je suis en train d'écrire un émulateur Chip8 et le vérificateur d'emprunt me donne un moment difficile.Comment stocker des pointeurs de méthode dans un HashMap et les appeler

L'idée est de décoder un opcode grâce à la recherche un pointeur à l'intérieur d'un HashMap puis l'exécution de ce pointeur de méthode méthode, mais je ne peux pas obtenir les pointeurs de méthode mutables correctement travail:

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

Fonction en utilisant les pointeurs:

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; 
} 

Le vérificateur se plaint:

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 

Je ne comprends pas pourquoi cette erreur se produit.

Pourquoi est-self.jump_table.get(&key) emprunt du tout? Basé sur la signature de execute_decoded, je supposais que cela fonctionne sur une version empruntée mutable de self et aucun emprunt supplémentaire n'est nécessaire.

Répondre

2

A HashMap à Rust possède tout à l'intérieur de celui-ci. Pour obtenir votre pointeur de fonction, vous l'empruntez avec let func = self.jump_table.get(&key);. Alors maintenant, func est emprunter immuablementself.jump_table (qui est un élément de self). Le problème est que vous essayez ensuite de passer tous self en func. Ce serait bien si vous passiez dans self immuablement, car vous pouvez emprunter self autant de fois que vous le souhaitez. Toutefois, étant donné que vous essayez d'emprunter mutably self le compilateur ne vous permettra pas de le faire puisque vous venez immuablement emprunté une partie de self (en particulier self.jump_table). Une façon de résoudre ce problème est de diviser votre struct Chip8 en structures plus petites, de sorte que vous pouvez transmettre toutes les informations nécessaires dans func sans passer également dans jump_table.

+1

Fin de la pensée, le compilateur ne peut pas garantir que 'func' ne * changement *' self' telle qu'elle est invalidée, comme par effacement de la carte de hachage. – Shepmaster

4

Il n'y a aucune raison pour Box les pointeurs de fonction dans le HashMap, qui introduit uniquement l'indirection inutile.

Comme cela a already been mentioned, vous empruntez le pointeur de fonction. La chose est, il n'y a aucune raison de. Vous pouvez simplement copier le pointeur de fonction pour dissocier de l'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() {}