0

我正在用 Rust 编写一个简单的库来管理一副纸牌。它具有洗牌、发牌等功能。

shuffle() 函数采用对 self 的可变引用,允许重新洗牌现有的牌组。它应该非常简单:

  1. 从卡片组创建一个临时集合,其中包含一个带有卡片和随机数的元组。
  2. 按随机数对集合进行排序。
  3. 使用临时集合的顺序重建现有的牌组。

代码如下。

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

}

我遇到的问题是这不会编译,因为我收到错误。

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     }                                                                            

这些错误抱怨可变性,我认为这意味着它不喜欢我在范围内有多个可变引用或其他东西,但我不知道如何修复它。我尝试使用大括号分隔符为每个操作制作块,但无济于事。我可能可以将其分解为多个函数,但我宁愿它是一个函数。我如何以最少的努力完成这项工作?

注意,我还没有测试排序功能,所以我希望 sort_by_key 能按照我的想法做,但这只有在我解决了第一个问题之后才有意义。

4

1 回答 1

2

shuffleris of type Vec<(&Card, u32)>,即 thecard是一个引用。也就是说,它是指向Card存储在self.cards向量下的缓冲区中的对象的指针。所以self.cards.clear()才会删除shuffler脚下的记忆!

幸运的是,有一个简单的解决方法:不要引用并清除向量,将卡片移出 self.cardswith drain

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

另外:有一种就地洗牌算法也比排序更有效——线性时间而不是 O(n log n),以及更好的常数因子——Fisher-Yates shuffle

于 2016-04-02T21:10:46.787 回答