在Rust中自我和集合的可变性问题

时间:2016-04-02 21:00:26

标签: rust mutability

我在Rust写一个管理一副牌的simple library。它具有洗牌,发牌等功能。

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

  1. 从包含带有卡片和随机数的元组的卡片组创建临时收藏。
  2. 按随机数对集合进行排序。
  3. 使用临时收集的顺序重建现有的牌组。
  4. 此代码如下:

     library(Rlab)
     bplot(MY,S)
    

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

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

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

    注意我尚未测试排序功能,所以我希望sort_by_key做我认为的事情,但在解决第一个问题之后,这只会变得很重要。

1 个答案:

答案 0 :(得分:2)

shuffler属于Vec<(&Card, u32)>类型,即card引用。也就是说,它是存储在Card向量下面的缓冲区中的self.cards对象的指针。因此self.cards.clear()会删除shuffler脚下的内存!

幸运的是,有一个简单的解决方法:不要参考并清除矢量,使用self.cards将卡片移出 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