5.1.4. 生成自定义类型随机值
问题:
你想取得一个随机值,但随机值类型并非标量,而是自定义类型。
解决方案:
假设我们需要随机生成一个元组 (i32, bool, f64)
,和一个用户定义类型为 Point
的变量。对于随即元组 (i32, bool, f64)
,如同前几个小结生成标量随机值一样,可以通过 rng.gen::<(i32, bool, f64)>()
直接生成。
而对于随机生成用户定义类型 Point
的变量,则需要使用通用的随机值分布结构体。rand crate 中,定义了一个结构体 Standard
,它是通用的随机值分布结构体,通常生成均匀分布的数值,并且具有与类型相适应的范围。我们已经了解,Distribution
是用于创建概率分布类型的 trait。因此,我们需要为 Standard
实现 Distribution
trait,以允许随机生成。
以下实例代码引用自开源书籍项目《Cookin’ with Rust》,笔者在其基础上稍作修改。
use rand::Rng; use rand::distributions::{Distribution, Standard}; #[derive(Debug)] struct Point { x: i32, y: i32, } impl Distribution<Point> for Standard { fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Point { let (rand_x, rand_y) = rng.gen(); Point { x: rand_x, y: rand_y, } } } fn main() { let mut rng = rand::thread_rng(); let rand_tuple = rng.gen::<(i32, bool, f64)>(); let rand_point: Point = rng.gen(); println!(" 随机值元组: {:?}", rand_tuple); println!(" 随机值结构体: {:?}", rand_point); }
这段代码行数虽多,但逻辑不复杂。
代码第 1,2 行,使用 use
将相关模块引入作用域。
代码第 5-8 行,自定义一个结构体类型 Point
。
最主要的是代码第 10-18 行,为 Standard
实现 Distribution
trait,其中 Distribution
trait 的类型为结构体 Point
。这样可以在 sample
方法中,直接将产生的随机值封装到结构体 Point
。
构建并运行后,结果大抵如下所示。
随机值元组: (413049996, true, 0.19354408882040275)
随机值结构体: Point { x: 1087377718, y: -375119726 }
注:你的运行结果值和笔者运行结果不一定相同。
讨论:
对于用户自定义类型,我们需要使用通用的随机值分布结构体 Standard
,然后为结构体 Standard
实现 Distribution
trait。结构体 Standard
为 rand crate 中的众多基本类型实现,也可适用于用户自定义类型。而 Distribution
trait 则用于创建概率分布类型,可以用来创建泛型 T 的随机实例的类型。提供 sample_iter
方法,该方法生成一个迭代器,从分布中采样。