rand Crate (Rust): Shuffling, Sampling & RNGs Guide

Max WellsMax WellsFounder of Rustify

TL;DR: The rand crate is Rust's standard random number library. Use rand::random::<T>() for a quick random value, or create an rng with rand::rng() for repeated use. Generate numbers in a range with .random_range(lo..hi), shuffle a Vec with .shuffle(), and choose a random element with .choose(). For cryptographically secure randomness, use the rand::rngs::OsRng or the getrandom crate directly.


How Do You Generate Random Numbers?

# Cargo.toml
[dependencies]
rand = "0.9"
use rand::Rng;
 
fn main() {
    let mut rng = rand::rng();
 
    // Random integer in a range [lo, hi)
    let n: i32 = rng.random_range(1..=100);
    println!("roll: {n}");
 
    // Random float [0.0, 1.0)
    let f: f64 = rng.random();
    println!("float: {f:.4}");
 
    // Random bool with probability
    let heads: bool = rng.random_bool(0.5);
    println!("coin: {}", if heads { "heads" } else { "tails" });
 
    // Quick one-liner (new rng each time; ok for occasional use)
    let quick: u32 = rand::random();
    println!("quick: {quick}");
}

How Do You Shuffle and Sample Collections?

use rand::seq::SliceRandom;
use rand::Rng;
 
fn main() {
    let mut rng = rand::rng();
    let mut deck: Vec<u32> = (1..=52).collect();
 
    // Shuffle in place
    deck.shuffle(&mut rng);
    println!("first card: {}", deck[0]);
 
    // Choose a random element
    let items = vec!["apple", "banana", "cherry", "date"];
    if let Some(pick) = items.choose(&mut rng) {
        println!("chose: {pick}");
    }
 
    // Choose multiple (without replacement)
    let sample: Vec<&str> = items.choose_multiple(&mut rng, 2).copied().collect();
    println!("sample: {:?}", sample);
}

How Do You Generate Random Structs?

Use rand::distr::Standard or implement Distribution<T> for custom types.

use rand::{Rng, distr::{Distribution, Standard}};
 
#[derive(Debug)]
enum Direction { North, South, East, West }
 
impl Distribution<Direction> for Standard {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Direction {
        match rng.random_range(0..4) {
            0 => Direction::North,
            1 => Direction::South,
            2 => Direction::East,
            _ => Direction::West,
        }
    }
}
 
fn main() {
    let mut rng = rand::rng();
    let dir: Direction = rng.random();
    println!("{dir:?}");
}

What Random Number Generators Are Available?

RNGUse caseNotes
rand::rng()General purposeDefault, seeded from OS
rand::rngs::SmallRngFast, not crypto-safeSeed manually for reproducibility
rand::rngs::StdRngReproducible, seededGood for tests and simulations
rand::rngs::OsRngCryptographicReads from OS entropy source
use rand::{SeedableRng, Rng};
use rand::rngs::StdRng;
 
// Reproducible: same seed → same sequence
let mut rng = StdRng::seed_from_u64(42);
let values: Vec<i32> = (0..5).map(|_| rng.random_range(1..=100)).collect();
println!("{values:?}");  // always the same sequence

Frequently Asked Questions

Yes; rand::random() and rand::rng() use a thread-local RNG internally. Each thread has its own generator, seeded independently from the OS.

Use OsRng when generating cryptographic material (tokens, session IDs, keys). Use rand::rng() for simulations, games, shuffles, and anything where predictability is acceptable. Never use rand::rng() for password hashing or secret generation.

Use the uuid crate with the v4 feature:

let id = uuid::Uuid::new_v4(); // uses OsRng internally

Seed the RNG with a fixed value in tests:

let mut rng = rand::rngs::StdRng::seed_from_u64(12345);

Or use proptest / quickcheck for property-based testing with automatic seed management.


Sources


  • UUID: UUID v4 uses random number generation
  • Iterator: rand integrates with iterators for sampling
  • Vec: .shuffle() works on Vec<T>
  • Bevy: Game logic and simulation code often rely on rand for procedural behavior and testing
  • proptest: Randomized data generation is conceptually adjacent to property testing strategies

Keep Reading

Ready to Land a $120k+ Rust Job in the US or Europe?