5.1.6. 从用户定义字符创建随机密码

rand-badge cat-os-badge

问题:

你想设定一组自定义字符,然后从此自定义字符范围内生成一个随机值,比如创建只包含小写字母、数字,以及特殊字符的随机密码。

解决方案:

使用用户自定义的字节字符串,使用 gen_range 函数,随机生成一个给定长度的 ASCII 字符串。

以下实例代码引用自开源书籍项目《Cookin’ with Rust》,笔者在其基础上稍作修改。

use rand::Rng;

fn main() {
    const CHARSET: &[u8] = b"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);
}

代码第 1 行,我们使用 use 关键字将 rand::Rng 引入作用域。rand::Rng 是在 RngCore trait 上自动实现的扩展 trait,它实现了高层次的泛型方法。

代码第 3,4 行,自定义字节字符串样本,并设定密码长度。

代码第 11 行,通过 0..PASSWORD_LEN 匹配一个闭区间范围,其是密码字符串的长度。

代码第 12-15 行,首先在 map 方法内,通过闭包从自定义字节字符串样本中取随机值,其将根据密码字符串的长度迭代产生。然后通过 collect 方法绑定到变量 password

构建并运行后,结果大抵如下所示。

  随机密码: "5%6y$upw4j1!w!mt)fw%)p^&b7xp($"

注:你的运行结果值和笔者运行结果不一定相同。

讨论:

gen_range 函数在 [低位,高位] 范围内生成一个随机值。此范围为半开放范围,即包括低位而不包括高位。此函数针对给定范围内仅生成一个样本值的情况进行了优化。另外,此函数为均匀分布类型,如果从相同的范围重复抽样取值,执行速度将会更快。