# 生成随机值

### 生成随机数

使用 rand::thread_rng 可以获取一个随机数生成器 rand::Rng ，该生成器需要在每个线程都初始化一个。

整数的随机分布范围等于类型的取值范围，但是浮点数只分布在 `[0, 1)` 区间内。

    use rand::Rng;

    fn main() {
        let mut rng = rand::thread_rng();

        let n1: u8 = rng.gen();
        let n2: u16 = rng.gen();
        println!("Random u8: {}", n1);
        println!("Random u16: {}", n2);
        println!("Random u32: {}", rng.gen::<u32>());
        println!("Random i32: {}", rng.gen::<i32>());
        println!("Random float: {}", rng.gen::<f64>());
    }

### 指定范围生成随机数

使用 Rng::gen_range 生成 [0, 10) 区间内的随机数( 右开区间，不包括 `10` )。

    use rand::Rng;

    fn main() {
        let mut rng = rand::thread_rng();
        println!("Integer: {}", rng.gen_range(0..10));
        println!("Float: {}", rng.gen_range(0.0..10.0));
    }

Uniform 可以用于生成均匀分布uniform distribution的随机数。当需要在同一个范围内重复生成随机数时，该方法虽然和之前的方法效果一样，但会更快一些。

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

    fn main() {
        let mut rng = rand::thread_rng();
        let die = Uniform::from(1..7);

        loop {
            let throw = die.sample(&mut rng);
            println!("Roll the die: {}", throw);
            if throw == 6 {
                break;
            }
        }
    }

### 使用指定分布来生成随机数

默认情况下，`rand` 包使用均匀分布来生成随机数，而 rand_distr 包提供了其它类型的分布方式。

首先，你需要获取想要使用的分布的实例，然后在 rand::Rng 的帮助下使用 Distribution::sample 对该实例进行取样。

如果想要查询可用的分布列表，可以访问这里，下面的示例中我们将使用 Normal 分布:

    use rand_distr::{Distribution, Normal, NormalError};
    use rand::thread_rng;

    fn main() -> Result<(), NormalError> {
        let mut rng = thread_rng();
        let normal = Normal::new(2.0, 3.0)?;
        let v = normal.sample(&mut rng);
        println!("{} is from a N(2, 9) distribution", v);
        Ok(())
    }

### 在自定义类型中生成随机值

使用 Distribution 特征包裹我们的自定义类型，并为 Standard 实现该特征，可以为自定义类型的指定字段生成随机数。

    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();

        // 生成一个随机的 Point
        let rand_point: Point = rng.gen();
        println!("Random Point: {:?}", rand_point);

        // 通过类型暗示( hint )生成一个随机的元组
        let rand_tuple = rng.gen::<(i32, bool, f64)>();
        println!("Random tuple: {:?}", rand_tuple);
    }

### 生成随机的字符串(A-Z, a-z, 0-9)

通过 Alphanumeric 采样来生成随机的 ASCII 字符串，包含从 `A-Z, a-z, 0-9` 的字符。

    use rand::{thread_rng, Rng};
    use rand::distributions::Alphanumeric;

    fn main() {
        let rand_string: String = thread_rng()
            .sample_iter(&Alphanumeric)
            .take(30)
            .map(char::from)
            .collect();

        println!("{}", rand_string);
    }

### 生成随机的字符串( 用户指定 ASCII 字符 )

通过 gen_string 生成随机的 ASCII 字符串，包含用户指定的字符。

    fn main() {
        use rand::Rng;
        const CHARSET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ\
                                abcdefghijklmnopqrstuvwxyz\
                                0123456789)(*&^%$#@!~";
        const PASSWORD_LEN: usize = 30;
        let mut rng = rand::thread_rng();

        let password: String = (0..PASSWORD_LEN)
            .map(|_| {
                let idx = rng.gen_range(0..CHARSET.len());
                CHARSET[idx] as char
            })
            .collect();

        println!("{:?}", password);
    }