Rust可变Vec引用移除元素时索引越界问题排查
Rust抽牌函数索引越界问题分析与修复
错误根源
你的代码核心问题是混淆了牌的数值和Vec的索引:
deck.choose(&mut rng)返回的是牌的数值(比如49,对应0-52的牌编号),你直接把这个数值当成swap_remove的索引参数。- 但随着牌组不断被移除元素,Vec的长度会逐渐缩短(比如抽完手牌后只剩50张,再抽牌后只剩49张),此时牌的数值(比如49)可能远大于当前Vec的最大有效索引(比如48),触发索引越界panic。
修复后的代码
use rand::seq::SliceRandom; mod cards; fn get_random_i(deck: &mut Vec<u16>) -> u16 { let mut rng = rand::thread_rng(); // 获取随机有效索引,而非元素值 let idx = deck.choose_index(&mut rng).unwrap(); // 通过索引移除元素并直接返回该元素 deck.swap_remove(idx) } fn get_random_hand(deck: &mut Vec<u16>) -> Vec<u16> { (0..2).map(|_| get_random_i(deck)).collect() } fn get_random_board(deck: &mut Vec<u16>) -> Vec<u16> { (0..5).map(|_| get_random_i(deck)).collect() } fn main() { let mut deck: Vec<u16> = (0..52).collect(); let hand = get_random_hand(&mut deck); let board = get_random_board(&mut deck); println!( "{}, {}", cards::CARDS[hand[0] as usize], cards::CARDS[hand[1] as usize] ); }
关键说明
- 使用
choose_index替代choose:choose_index直接返回Vec的随机有效索引,范围始终是0..deck.len(),不会出现越界问题。 - 利用
swap_remove的返回值:swap_remove在移除指定索引元素的同时,会返回该元素的值,无需额外复制操作,代码更简洁高效。 - Rust与JS的差异:Rust中Vec的索引是元素在容器中的位置,和元素本身的数值完全独立——你用0-52初始化Vec时,元素值和索引暂时一致,但移除元素后,后续元素会被交换到被移除的索引位置,此时元素值和索引就不再对应了,这和JS数组的行为一致,但你之前错误地将元素值等同于索引使用。
内容的提问来源于stack exchange,提问作者methodical
相关产品推荐
相关产品推荐

