🎓 A1Learner
🔍

Rust Random Values

Random values are values a generator picks by chance. The rand crate hands out random values of many basic types.

Any basic type

Call rand::rng() once, keep the generator, then ask it for whatever type you need with random(). The type comes from the annotation. (The prelude brings random and its friends into scope. That prelude is use rand::prelude::*;.)

let mut rng = rand::rng();
let coin: bool = rng.random();
let letter: char = rng.random();
let fraction: f64 = rng.random();

A value inside a range

random_range picks from a..b (b left out) or a..=b (both ends in) — the same call the Guessing Game used for its secret.

let die = rng.random_range(1..=6);
let ticket = rng.random_range(1000..2000);

The same die, many rolls (a distribution)

Some ranges get used over and over. For those, build a Uniform once. Then sample it. It reads like the thing it is.

use rand::distr::{Distribution, Uniform};

let die = Uniform::new_inclusive(1, 6).expect("the range is valid");
let roll = die.sample(&mut rng);

Pick and shuffle a list

shuffle scrambles in place. choose pulls one Option out. Both need the generator.

let mut cards = ["A", "K", "Q", "J"];
cards.shuffle(&mut rng);
let pick = cards.choose(&mut rng);

Random text (a password)

Alphanumeric hands out one letter-or-digit at a time. The loop asks ten times and pushes each character into a String:

use rand::distr::Alphanumeric;

let mut key = String::new();
for _ in 0..10 {
    key.push(rng.sample(Alphanumeric) as char);
}

Custom values from random parts

Write a tiny helper. It rolls the parts. It returns your own type. There is no new trait. It is just a function. The function borrows the generator.

fn random_point(rng: &mut rand::rngs::ThreadRng) -> (i32, i32) {
    (rng.random_range(-5..=5), rng.random_range(-5..=5))
}

let spot = random_point(&mut rng);

A whole array of bytes at once

fill writes random bytes into a whole array in one call. Tokens and ids start life as bytes like these.

let mut bytes = [0u8; 8];
rng.fill(&mut bytes);

Example

use rand::prelude::*;
use rand::rngs::StdRng;

fn main() {
    let mut rng = StdRng::seed_from_u64(7);
    println!("die 1 = {}", rng.random_range(1..=6));
    println!("die 2 = {}", rng.random_range(1..=6));
    println!("die 3 = {}", rng.random_range(1..=6));
    println!("heads = {}", rng.random_bool(0.5));
    let colours = ["red", "green", "blue", "gold"];
    println!("colour = {:?}", colours.choose(&mut rng));
}

Key points

  • rand is a library.
  • It is not part of std.
  • Add rand = "0.10" under [dependencies] in Cargo.toml.
  • The Guessing Game used the same line.
  • rand::rng() hands you the thread generator.
  • Call it once.
  • Keep it in a variable.
  • Every method needs &mut.
  • Values are uniform: every value in the range is equally likely — the die has no memory.
  • Use fill to fill a whole byte array in one call.
  • It is the raw material for tokens, salts and ids

Seed 7 makes the generator replay one fixed sequence. So this program prints the same five lines every run. The values above are exactly what seed 7 gives. Change 7 to any other number. You get a different sequence. It is still repeatable. rand::rng() would give fresh values each time. choose returns Option because the list could be empty.

Note

rand::rng() seeds itself from the operating system, so its output differs every run.

A seeded generator repeats the same sequence.

The final example shows one.

Use it in tests.

Use it anywhere you must replay the "randomness".

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

Why does the closing example print the exact same lines on every run?