3.7 随机值

原文链接: https://rust-random.github.io/book/guide-values.html

既然有了产生随机数据的方法,如何将其转换为我们想要的值类型?

这是个「陷阱」式问题:我们需要同时知道想要的范围和值的分布类型(这正是下一节的内容)。

Rng trait

为方便起见,所有生成器自动实现 Rng trait,它提供了几种生成值的快捷方式。其中有若干产生均匀分布值的便捷函数:

  • Rng::random 从适合该类型的范围生成无偏(均匀)随机值。对整数通常是完整可表示范围(例如从 0u32 到 std::u32::MAX),对浮点数是 0 到 1 之间,还支持数组、元组等其他类型。

    该方法是 StandardUniform 分布的便捷封装,详见下一节。

  • Rng::random_range 在给定范围内生成无偏随机值

  • Rng::fill 和 Rng::try_fill 是用随机值填充任意字节或整数切片的优化函数

还有产生非均匀布尔值的便捷函数:

最后,有从任意分布采样的函数:

示例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
use rand::RngExt;
# fn main() {
let mut rng = rand::rng();

// 整个范围内的无偏整数:
let i: i32 = rng.random();
println!("i = {i}");

// 0 到 1 之间均匀分布的值:
let x: f64 = rng.random();
println!("x = {x}");

// 模拟掷骰子:
println!("roll = {}", rng.random_range(1..=6));
# }

此外,random 函数是对 rng() 上 Rng::random 的快捷方式:

1
2
3
4
5
6
7
# use rand::Rng;
# fn main() {
println!("Tossing a coin...");
if rand::random() {
    println!("We got lucky!");
}
# }

自定义随机类型

注意上面 rng.random() 根据类型产生不同分布的值:

  • i32 值从 i32::MIN ..= i32::MAX 均匀采样
  • f32 值从 0.0 .. 1.0 均匀采样

这就是 StandardUniform 分布。Distribution 是下一章的主题,但鉴于 StandardUniform 的重要性,在此介绍。惯例多少有些任意,但按合理逻辑选择:

  • 值均匀采样:给定任意两个等长子范围,每个包含下一个采样值的概率相等
  • 通常使用目标类型的整个范围
  • 对 f32 和 f64 使用 0.0 .. 1.0 范围(不含 1.0),原因有二:(a) 这是随机数生成器的常见做法;(b) 对许多用途而言,在实数轴上均匀分布的样本很重要,而对浮点表示这只能通过限制范围实现。

据此,我们可以为自己的类型实现 StandardUniform 分布:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
use rand::{Rng, RngExt};
use rand::distr::{Distribution, StandardUniform, Uniform};
use std::f64::consts::TAU; // = 2π

/// 表示弧度制角度
#[derive(Debug)]
pub struct Angle(f64);
impl Angle {
    pub fn from_degrees(degrees: f64) -> Self {
        Angle(degrees * (std::f64::consts::TAU / 360.0))
    }
}

impl Distribution<Angle> for StandardUniform {
    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Angle {
        // 这样写是正确的:
        // Angle(rng.random::<f64>() * TAU)

        // 但下面这种写法更推荐:
        Angle(Uniform::new(0.0, TAU).unwrap().sample(rng))
    }
}

fn main() {
    let angle: Angle = rand::rng().random();
    println!("Random angle: {angle:?}");
}
最后修改 August 23, 2026: 更新 (499855b16)