外观
第 5 节:rand——随机数与洗牌
一句话:第 1 章猜拳、第 2 章猜数字用的就是它。这一节把 rand 0.9 的家底过一遍:随机整数/小数、随机挑、洗牌,还有真实的坑。
安装
bash
cargo add rand高频四件套 ⭐
1. 随机整数
rust
use rand::Rng;
let mut rng = rand::rng();
let dice = rng.random_range(1..=6); // 1~6(闭区间)random_range 的参数是区间:1..=6(含 6)或 0..10(不含 10)——和 1..=100 的秘密数字(第 2 章)一个脾气。
2. 随机小数
rust
let ratio = rng.random::<f64>(); // 0.0 ~ 1.0random::<T>() 生成"标准范围"的任意类型:布尔、char、f64……想 0~100 的小数,rng.random::<f64>() * 100.0。
3. 从数组随机挑
rust
let choices = ["石头", "剪刀", "布"];
let pick = choices[rng.random_range(0..choices.len())];第 1 章猜拳的原版(当时用 rand::rng().random_range(0..3))。
4. 洗牌 / 抽一张
rust
use rand::seq::SliceRandom;
let mut deck: Vec<u32> = (1..=10).collect();
deck.shuffle(&mut rng); // 原地洗牌
let winner = deck.choose(&mut rng); // 随机抽一个(返回 Option)真实的坑:API 迁移 ⭐
rand 0.9 改了不少 API 名,老教程的写法会编译不过:
| 老写法(0.8) | 新写法(0.9) |
|---|---|
rand::thread_rng() | rand::rng() |
gen_range(0..10) | random_range(0..10) |
rand::random() | rng.random::<T>() 或 rand::random::<T>() |
slice.choose(&mut rng) | 需要 use rand::prelude::IndexedRandom;(编译错误篇雷区 9 的现场!) |
遇到"方法找不到",先看是不是 API 迁移——rust-analyzer 会提示 use rand::prelude::...,照着加就行(第 9 节那个 E0599 就是这么回事)。
常见误用与坑
- 忘
use rand::Rng;:random_range/random是Rngtrait 的方法(第 1 章的旧账,use rand::Rng;是标配) - 每轮循环里
rand::rng():创建随机源有开销,循环外建一次(let mut rng = rand::rng();),循环里rng.random_range(...) choose忘IndexedRandom:rand 0.9 的choose/shuffle分属不同 trait,SliceRandom管shuffle,IndexedRandom管choose/choose_multiple- "伪随机"够用吗:默认的随机源(ChaCha)质量足够(游戏、抽样);要密码学安全用
rand_core+getrandom方向,或直接getrandomcrate - 测试要可复现?:自己造种子
StdRng::seed_from_u64(42)——需要rand::SeedableRng(第 10 章测试的"固定随机"技巧)