2016-04-02 5 views
0

ich simple library in Rust schreibe, die ein Kartenspiel verwaltet. Es verfügt über Funktionen zu mischen, abkomme Karten etc.Mutability Problem mit sich selbst und Sammlungen in Rust

Die shuffle() Funktion, um einen veränderbaren Bezug auf mich selbst nimmt, dass das bestehende Deck erlaubt neu gemischt werden. Es sollte ziemlich einfach sein:

  1. Erstellen Sie eine temporäre Sammlung aus dem Deck mit einem Tupel mit einer Karte und einer Zufallszahl.
  2. Sortieren Sie die Sammlung nach der Zufallszahl.
  3. Umbau der bestehenden Plattform, welche die Reihenfolge der temporären Sammlung verwenden.

Der Code für diese würde wie folgt sein.

pub struct Deck { 
    // A deck contains zero or more cards 
    cards: Vec<Card> 
} 

impl Deck { 

// shuffle 
pub fn shuffle(&mut self) { 
    if self.cards.is_empty() { 
     return; 
    } 

    let mut shuffler : Vec<(&Card, u32)> = Vec::with_capacity(self.cards.len()); 

    for card in self.cards.iter() { 
     // make a tuple consisting of each card in the input and a random number 
     let card_pos = (card, rand::thread_rng().gen::<u32>()); 
     shuffler.push(card_pos); 
    } 

    // Sort the vector 
    shuffler.sort_by_key(|k| k.1); 

    // Clear the cards 
    self.cards.clear(); 

    // Put the cards into the new randomized order 
    for card_pos in shuffler { 
     let (card, _) = card_pos; 
     self.cards.push(*card) 
    } 
} 

} 

Das Problem, das ich habe, ist dies wird nicht kompilieren, weil ich Fehler bekomme.

src\deck.rs:85:9: 85:19 error: cannot borrow `self.cards` as mutable because it is also borrowed as immutable [E0502]                       
src\deck.rs:85   self.cards.clear();                
         ^~~~~~~~~~                  
src\deck.rs:75:15: 75:25 note: previous borrow of `self.cards` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `self.cards` until the borrow ends        
src\deck.rs:75   for card in self.cards.iter() {             
            ^~~~~~~~~~               
src\deck.rs:92:6: 92:6 note: previous borrow ends here             
src\deck.rs:68  pub fn shuffle(&mut self) {               
...                          
src\deck.rs:92  }                      
       ^                     
src\deck.rs:90:13: 90:23 error: cannot borrow `self.cards` as mutable because it is also borrowed as immutable [E0502]                       
src\deck.rs:90    self.cards.push(*card)              
          ^~~~~~~~~~                 
src\deck.rs:75:15: 75:25 note: previous borrow of `self.cards` occurs here; the immutable borrow prevent 
s subsequent moves or mutable borrows of `self.cards` until the borrow ends        
src\deck.rs:75   for card in self.cards.iter() {             
            ^~~~~~~~~~               
src\deck.rs:92:6: 92:6 note: previous borrow ends here             
src\deck.rs:68  pub fn shuffle(&mut self) {               
...                          
src\deck.rs:92  }                    

Die Fehler klagen über Veränderlichkeit, die ich nehme an zu verstehen, dass es nicht so, dass ich mehr als eine veränderbare Referenz in Umfang oder etwas habe, aber ich weiß nicht, wie es zu beheben. Ich habe versucht, Klammernbegrenzer zu verwenden, um Blöcke für jede Aktion zu machen, aber ohne Erfolg. Ich könnte das wahrscheinlich in mehr als eine Funktion aufteilen, aber ich hätte lieber eine einzige Funktion. Wie mache ich das mit möglichst wenig Aufwand?

NB Ich habe nicht die Sortierfunktion noch nicht getestet, so hoffe ich, sort_by_key tut, was ich denke, aber das ist nur, nachdem ich dieses erste Problem beheben gehen Rolle zu spielen.

Antwort

2

shuffler ist vom Typ Vec<(&Card, u32)>, das heißt die card a Referenz. Das heißt, es ist ein Zeiger auf das Objekt Card, das in dem Puffer gespeichert ist, der dem Vektor self.cards unterliegt. So self.cards.clear() würde den Speicher unter shuffler Füße löschen!

Zum Glück gibt eine einfache Lösung ist: Verwenden Sie keine Referenzen nehmen und den Vektor zu löschen, die Karten ausself.cards mit drain bewegen:

let mut shuffler: Vec<(Card, u32)> = Vec::with_capacity(self.cards.len()); 
for card in self.cards.drain(..) { 
    let card_pos = (card, rand::thread_rng().gen::<u32>()); 
    shuffler.push(card_pos); 
} 
shuffler.sort_by_key(|k| k.1); 
for card_pos in shuffler { 
    let (card, _) = card_pos; 
    self.cards.push(card); 
} 

Abgesehen: Es gibt einen in-Place-schlurfenden Algorithmus, effizienter ist auch als — lineare Zeit statt O (n log n) und eine bessere konstante Faktoren — die Fisher-Yates shuffle Sortierung.

+0

Danke, das hat den Trick gemacht. Ich hatte vorher versucht, ohne Refs zu verwenden, und ich bekam andere Fehler, aber von ähnlicher Art. Ich werde den Shuffle-Algorithmus im Hinterkopf behalten, da ich ihn genauso effizient wie möglich gestalten kann. – locka

Verwandte Themen