You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

关键说明

  1. 使用choose_index替代choose:choose_index直接返回Vec的随机有效索引,范围始终是0..deck.len(),不会出现越界问题。
  2. 利用swap_remove的返回值:swap_remove在移除指定索引元素的同时,会返回该元素的值,无需额外复制操作,代码更简洁高效。
  3. Rust与JS的差异:Rust中Vec的索引是元素在容器中的位置,和元素本身的数值完全独立——你用0-52初始化Vec时,元素值和索引暂时一致,但移除元素后,后续元素会被交换到被移除的索引位置,此时元素值和索引就不再对应了,这和JS数组的行为一致,但你之前错误地将元素值等同于索引使用。

内容的提问来源于stack exchange,提问作者methodical

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 17:22:53