Loading page…
Rust walkthroughs
Loading page…
Rand is the de facto standard library for random number generation in Rust. It provides a unified interface for various random number generators (RNGs), distributions, and utilities for generating random values. Rand supports both cryptographically secure and non-secure random number generation, making it suitable for games, simulations, cryptography, and more.
Key concepts:
When to use Rand:
When NOT to use Rand:
use rand::Rng;
fn main() {
let mut rng = rand::thread_rng();
// Random integer in range [0, 100)
let n: i32 = rng.gen_range(0..100);
println!("Random number: {}", n);
// Random float in range [0.0, 1.0)
let f: f64 = rng.gen();
println!("Random float: {}", f);
// Random boolean
let b: bool = rng.gen();
println!("Random bool: {}", b);
}use rand::Rng;
fn main() {
let mut rng = rand::thread_rng();
// Exclusive range [1, 10)
let n1: i32 = rng.gen_range(1..10);
println!("1-9: {}", n1);
// Inclusive range [1, 10]
let n2: i32 = rng.gen_range(1..=10);
println!("1-10: {}", n2);
// Float range
let f: f64 = rng.gen_range(0.0..1.0);
println!("Float: {}", f);
// Character range
let c: char = rng.gen_range('a'..='z');
println!("Letter: {}", c);
}use rand::seq::SliceRandom;
use rand::thread_rng;
fn main() {
let mut rng = thread_rng();
let choices = vec!["apple", "banana", "cherry", "date", "elderberry"];
// Choose a random element
if let Some(fruit) = choices.choose(&mut rng) {
println!("Random fruit: {}", fruit);
}
// Choose multiple random elements
let sampled: Vec<_> = choices.choose_multiple(&mut rng, 3).collect();
println!("Sampled: {:?}", sampled);
// Shuffle the collection
let mut numbers: Vec<i32> = (1..=10).collect();
numbers.shuffle(&mut rng);
println!("Shuffled: {:?}", numbers);
}use rand::Rng;
use rand::distributions::{Alphanumeric, DistString};
fn main() {
let mut rng = rand::thread_rng();
// Random alphanumeric string
let s: String = Alphanumeric.sample_string(&mut rng, 16);
println!("Random string: {}", s);
// Random string from custom characters
const CHARSET: &[u8] = b"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
let password: String = (0..20)
.map(|_| {
let idx = rng.gen_range(0..CHARSET.len());
CHARSET[idx] as char
})
.collect();
println!("Password: {}", password);
}use rand::{Rng, SeedableRng};
use rand::rngs::StdRng;
fn main() {
// Create RNG with fixed seed for reproducibility
let seed: u64 = 42;
let mut rng1 = StdRng::seed_from_u64(seed);
let mut rng2 = StdRng::seed_from_u64(seed);
// Both will produce the same sequence
let n1: i32 = rng1.gen_range(0..100);
let n2: i32 = rng2.gen_range(0..100);
println!("rng1: {}, rng2: {}", n1, n2);
assert_eq!(n1, n2); // Always true
}use rand::Rng;
fn main() {
let mut rng = rand::thread_rng();
// Random tuple
let point: (f64, f64) = rng.gen();
println!("Random point: ({}, {})", point.0, point.1);
// Random array
let arr: [u8; 8] = rng.gen();
println!("Random bytes: {:02x?}", arr);
// Fill existing array
let mut buffer = [0u8; 32];
rng.fill(&mut buffer);
println!("Buffer: {:02x?}", buffer);
}use rand::distributions::{Distribution, Uniform, Normal, Alphanumeric};
use rand::thread_rng;
fn main() {
let mut rng = thread_rng();
// Uniform distribution (default for gen_range)
let uniform = Uniform::from(0..100);
let n: i32 = uniform.sample(&mut rng);
println!("Uniform: {}", n);
// Normal (Gaussian) distribution
let normal = Normal::new(0.0, 1.0).unwrap(); // mean=0, std_dev=1
let gaussian: f64 = normal.sample(&mut rng);
println!("Gaussian: {}", gaussian);
// Sample multiple values
let values: Vec<f64> = normal.sample_iter(&mut rng).take(5).collect();
println!("Multiple: {:?}", values);
}use rand::seq::IteratorRandom;
use rand::thread_rng;
fn main() {
let mut rng = thread_rng();
let items = vec![('a', 1), ('b', 2), ('c', 3), ('d', 4)];
// Weighted selection (simplified approach)
let total_weight: i32 = items.iter().map(|(_, w)| w).sum();
let choice = rng.gen_range(1..=total_weight);
let mut cumulative = 0;
for (item, weight) in items {
cumulative += weight;
if choice <= cumulative {
println!("Selected: {}", item);
break;
}
}
}use rand::distributions::{Distribution, Bernoulli};
use rand::thread_rng;
fn main() {
let mut rng = thread_rng();
// 70% chance of success
let bernoulli = Bernoulli::new(0.7).unwrap();
let mut successes = 0;
for _ in 0..100 {
if bernoulli.sample(&mut rng) {
successes += 1;
}
}
println!("Successes: {}/100", successes);
}use rand::rngs::OsRng;
use rand::RngCore;
fn main() {
let mut rng = OsRng;
// Cryptographically secure random bytes
let mut key = [0u8; 32];
rng.fill_bytes(&mut key);
println!("Secure key: {:02x?}", key);
// Random u64
let secure_u64 = rng.next_u64();
println!("Secure u64: {}", secure_u64);
}use rand::Rng;
fn generate_uuid_v4() -> String {
let mut rng = rand::thread_rng();
let mut bytes = [0u8; 16];
rng.fill(&mut bytes);
// Set version to 4 (random)
bytes[6] = (bytes[6] & 0x0f) | 0x40;
// Set variant to RFC4122
bytes[8] = (bytes[8] & 0x3f) | 0x80;
format!(
"{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
bytes[0], bytes[1], bytes[2], bytes[3],
bytes[4], bytes[5],
bytes[6], bytes[7],
bytes[8], bytes[9],
bytes[10], bytes[11], bytes[12], bytes[13], bytes[14], bytes[15]
)
}
fn main() {
println!("UUID: {}", generate_uuid_v4());
}use rand::Rng;
use rand::distributions::{Distribution, Standard};
#[derive(Debug)]
enum Coin {
Heads,
Tails,
}
impl Distribution<Coin> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Coin {
if rng.gen_bool(0.5) {
Coin::Heads
} else {
Coin::Tails
}
}
}
fn main() {
let mut rng = rand::thread_rng();
// Now we can use gen() for Coin
let flip: Coin = rng.gen();
println!("Flipped: {:?}", flip);
// Multiple flips
let flips: Vec<Coin> = (0..5).map(|_| rng.gen()).collect();
println!("Flips: {:?}", flips);
}use rand::seq::SliceRandom;
use rand::thread_rng;
fn main() {
let mut rng = thread_rng();
// Full shuffle
let mut deck: Vec<&str> = vec![
"A♠", "2♠", "3♠", "4♠", "5♠", "6♠", "7♠", "8♠", "9♠", "10♠", "J♠", "Q♠", "K♠",
"A♥", "2♥", "3♥", "4♥", "5♥", "6♥", "7♥", "8♥", "9♥", "10♥", "J♥", "Q♥", "K♥",
];
deck.shuffle(&mut rng);
println!("First 5 cards: {:?}", &deck[..5]);
// Partial shuffle
let mut numbers: Vec<i32> = (1..=100).collect();
numbers.partial_shuffle(&mut rng, 5);
println!("First 5 after partial shuffle: {:?}", &numbers[..5]);
}use rand::seq::IteratorRandom;
use rand::thread_rng;
fn main() {
let mut rng = thread_rng();
// Sample from iterator without replacement
let sample: Vec<i32> = (1..=1000)
.choose_multiple(&mut rng, 5);
println!("Sampled 5 from 1000: {:?}", sample);
// Sample from array
let items = vec!["a", "b", "c", "d", "e", "f", "g", "h"];
let chosen: Vec<_> = items.iter().choose_multiple(&mut rng, 3);
println!("Chosen 3: {:?}", chosen);
}use rand::seq::index;
use rand::thread_rng;
fn main() {
let mut rng = thread_rng();
// Get random indices from a range
let indices: Vec<usize> = index::sample(&mut rng, 100, 5).into_iter().collect();
println!("Random indices from 0-99: {:?}", indices);
// Get all indices in random order
let shuffled: Vec<usize> = index::shuffle(&mut rng, 10).into_vec();
println!("Shuffled 0-9: {:?}", shuffled);
}use rand::Rng;
use rand::distributions::{Distribution, Uniform};
fn roll_die(sides: u32) -> u32 {
let mut rng = rand::thread_rng();
rng.gen_range(1..=sides)
}
fn roll_dice(count: u32, sides: u32) -> Vec<u32> {
let mut rng = rand::thread_rng();
let die = Uniform::from(1..=sides);
(0..count).map(|_| die.sample(&mut rng)).collect()
}
fn main() {
let mut rng = rand::thread_rng();
// Roll a d20
let d20 = roll_die(20);
println!("d20: {}", d20);
// Roll 2d6
let two_d6 = roll_dice(2, 6);
let sum: u32 = two_d6.iter().sum();
println!("2d6: {:?} = {}", two_d6, sum);
// Roll 4d6, drop lowest (D&D stat generation)
let mut rolls = roll_dice(4, 6);
rolls.sort();
let stat: u32 = rolls[1..].iter().sum();
println!("4d6 drop lowest: {:?} = {}", rolls, stat);
}use rand::{Rng, SeedableRng};
use rand::rngs::StdRng;
fn game_simulation(rng: &mut StdRng) -> i32 {
// Simulate game with random elements
let score: i32 = rng.gen_range(0..100);
score
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_deterministic() {
let mut rng1 = StdRng::seed_from_u64(42);
let mut rng2 = StdRng::seed_from_u64(42);
// Same seed = same results
assert_eq!(rng1.gen::<u32>(), rng2.gen::<u32>());
}
#[test]
fn test_game_simulation() {
let mut rng = StdRng::seed_from_u64(12345);
let score = game_simulation(&mut rng);
// Deterministic score for testing
assert!(score >= 0 && score < 100);
}
}
fn main() {
let mut rng = StdRng::seed_from_u64(42);
let score = game_simulation(&mut rng);
println!("Score: {}", score);
}use rand::{Rng, SeedableRng};
use rand::rngs::StdRng;
use std::time::Instant;
fn benchmark_thread_rng(count: u32) -> u32 {
let mut rng = rand::thread_rng();
let mut sum = 0u32;
for _ in 0..count {
sum = sum.wrapping_add(rng.gen_range(0..1000));
}
sum
}
fn benchmark_std_rng(count: u32) -> u32 {
let mut rng = StdRng::from_entropy();
let mut sum = 0u32;
for _ in 0..count {
sum = sum.wrapping_add(rng.gen_range(0..1000));
}
sum
}
fn main() {
let iterations = 1_000_000;
let start = Instant::now();
benchmark_thread_rng(iterations);
let thread_duration = start.elapsed();
let start = Instant::now();
benchmark_std_rng(iterations);
let std_duration = start.elapsed();
println!("ThreadRng: {:?}", thread_duration);
println!("StdRng: {:?}", std_duration);
}use rand::Rng;
fn random_hex(length: usize) -> String {
let mut rng = rand::thread_rng();
(0..length)
.map(|_| format!("{:02x}", rng.gen::<u8>()))
.collect()
}
fn main() {
println!("Hex: {}", random_hex(16));
}Rand Key Imports:
use rand::Rng;
use rand::thread_rng;
use rand::seq::SliceRandom;
use rand::distributions::{Distribution, Uniform, Alphanumeric};RNG Types:
| Type | Description |
|------|-------------|
| thread_rng() | Thread-local, secure, convenient |
| StdRng | Reproducible, seedable |
| OsRng | Cryptographically secure from OS |
Core Methods:
| Method | Description |
|--------|-------------|
| gen() | Generate random value |
| gen_range(a..b) | Random in range |
| gen_bool(p) | Boolean with probability |
| fill(&mut buf) | Fill buffer with random bytes |
Distributions:
| Distribution | Description |
|--------------|-------------|
| Uniform | Equal probability in range |
| Normal | Gaussian distribution |
| Bernoulli | Boolean with probability |
| Alphanumeric | Random alphanumeric chars |
Sequence Operations:
| Method | Description |
|--------|-------------|
| choose() | Random element |
| choose_multiple() | Multiple random elements |
| shuffle() | Shuffle in place |
| partial_shuffle() | Partial shuffle |
Seeding:
// From entropy (random seed)
let rng = StdRng::from_entropy();
// From specific seed (reproducible)
let rng = StdRng::seed_from_u64(42);Key Points:
thread_rng() for most cases (fast, secure)StdRng with seed for reproducibilityOsRng for cryptographic securitySliceRandom for collection operationsAlphanumeric for random stringsgen_range(1..=10) for inclusive range