我在Rust写一个管理一副牌的simple library。它具有洗牌,发牌等功能。
shuffle()函数对self进行可变引用,允许对现有的deck进行重新洗牌。它应该非常简单:
此代码如下:
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做我认为的事情,但在解决第一个问题之后,这只会变得很重要。
答案 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。