4.1 升级到 0.5
7 分钟阅读
0.5 版本相比 0.4 版本有相当显著的变化;因此,阅读以下破坏性更改的说明可能值得。本版本还包含许多优化,下文未详细说明。
Crate
我们有了一个新 crate:rand_core!该 crate 包含一些重要的 trait:RngCore、BlockRngCore、SeedableRng 和 CryptoRng,错误类型,以及两个用于实现的辅助模块:le 和 impls。建议生成器的实现使用 rand_core crate,而其他用户仅使用 rand crate,它重新导出了 rand_core 的大部分内容。
rand_derive crate 由于使用率极低以及 Rand 的弃用而被弃用。
特性
添加了几个新的 Cargo 特性标志:
alloc,在没有std时使用,允许使用Box和Vecserde1为部分 PRNG 添加序列化支持log在少数地方添加日志(主要用于OsRng和JitterRng)
Rng 及其相关 trait(核心 trait)
Rng trait 已拆分为两个 trait:由生成器实现的「后端」RngCore 和实现所有便捷扩展方法的「前端」Rng。
生成器的实现必须改为 impl RngCore。鼓励实现使用 rand_core;rand_core::{le, impls} 模块可能很有用。
不需要实现 Rng 的 Rng 用户不需要做太多更改;通常用户可以忘记 RngCore 而只导入 Rng。用户应优先使用 Rng::gen() 而非 RngCore::next_u32() / next_u64(),使用 Rng::fill(dest) 而非 RngCore::fill_bytes(dest)。
Rng / RngCore 方法
为允许来自可能失败的源(例如 OsRng)的错误处理,添加了新方法 RngCore::try_fill_bytes;例如 EntropyRng 使用此机制在 OsRng 失败时回退到 JitterRng,各种处理器产生更好的错误消息。
与之前一样,其他方法在失败时会 panic,但由于这些通常与算法生成器一起使用且算法生成器通常不会失败,这被认为是适当的折衷。
旧 Rng 中的几个方法已被移除或弃用:
next_f32和next_f64;生成器不再能实现这些;改用gengen_iter;用户可以使用带闭包的标准迭代器:::std::iter::repeat(()).map(|()| rng.gen())gen_ascii_chars;如上使用repeat和rng.sample(Alphanumeric)gen_weighted_bool(n);改用gen_bool(1.0 / n)
Rng 有几个新方法:
sample(distr)是对任何Distribution的distr.sample(rng)的快捷方式gen_bool(p)生成布尔值,为 true 的概率为pfill和try_fill,分别对应fill_bytes和try_fill_bytes(即唯一区别是错误处理);这些可以直接填充整数切片/数组,并提供比gen()更好的性能
构造 PRNG
新的随机初始化 PRNG
添加了新 trait:FromEntropy。对于任何支持 SeedableRng 的类型自动实现,提供从新鲜、强熵构造:
| |
播种 PRNG
SeedableRng trait 已修改,通过关联类型(SeedableRng::Seed)包含种子类型,而非模板参数(SeedableRng<Seed>)。此外,所有 PRNG 现在都从字节数组播种([u8; N],N 为某个固定值)。这允许以前不可能的通用 PRNG 播种处理。
PRNG 不再通过 Rand 支持 / gen() 从其他 PRNG 构造,而是通过 SeedableRng::from_rng,它允许错误处理且刻意明确。
SeedableRng::reseed 已被移除,因为它相对于 from_seed 没有实用价值,且其性能优势值得质疑。
SeedableRng 的实现可能需要将其 Seed 类型更改为字节数组;此限制是为了确保可移植的字节序处理。rand_core::le 中有辅助函数可从字节数组读取 u32 和 u64 值。
基于块的 PRNG
rand_core 有新的辅助 trait BlockRngCore 和实现 BlockRng。这些供一次生成一块随机数据而非字大小值的生成器使用。使用此 trait 和实现有两个优势:提供优化的 RngCore 方法,且 PRNG 可以以非常低的开销与 ReseedingRng 一起使用。
密码学 RNG
添加了新 trait:CryptoRng。这纯粹是标记 trait,用于指示哪些生成器应适合密码学,例如 fn foo<R: Rng + CryptoRng>(rng: &mut R)。无法保证适合密码学用途。
错误处理
添加了新的 Error 类型,专为 no-std 兼容性、简洁性以及我们用途所需的足够灵活性(在可能时携带 cause)而设计:
| |
关联的 ErrorKind 允许将错误广泛分类为永久、意外、瞬态和尚未就绪类型。
以下使用新错误类型:
RngCore::try_fill_bytesRng::try_fillOsRng::newJitterRng::new
外部生成器
我们有了新生成器 EntropyRng,它包装 OsRng 和 JitterRng(优先使用前者,必要时回退到后者)。这允许通过 SeedableRng::from_rng 轻松构造并带回退,例如 IsaacRng::from_rng(EntropyRng::new())?。这与使用 FromEntropy 等价,除了错误处理。
建议在 OsRng 之上使用 EntropyRng 以避免系统生成器损坏的平台上的错误,但应注意 JitterRng 回退非常慢。
PRNG
伪随机数生成器(即确定性算法生成器)自 0.4 以来有一些变化,现在位于 prng 模块中(旧名称暂时保留以保持兼容性;最终这些生成器可能会放在 rand crate 之外)。
所有 PRNG 现在不实现 Copy,以防止意外复制生成器状态(从而导致生成值重复)。通过 Clone 的显式克隆仍然可用。所有 PRNG 现在都有不打印任何内部状态的自定义 Debug 实现;这有助于避免在日志文件中意外泄露密码学生成器状态。外部 PRNG 实现建议遵循此模式(另见 RngCore 文档)。
SmallRng 已作为包装器添加,目前围绕 XorShiftRng(但可能很快换用另一种算法)。这适用于小状态和快速初始化重要但不需要密码学强度的场景。(实际生成性能因基准测试而异;根据用法,这可能是最快的算法,也可能不是,但始终很快。)
ReseedingRng
ReseedingRng 包装器已显著修改以降低开销。不幸的是,新的 ReseedingRng 与所有 RNG 不兼容,仅与使用 BlockRngCore 的那些兼容。
ChaCha
ChaChaRng::set_counter 方法已被两个新方法 set_word_pos 和 set_stream 替换。必要时,旧方法的行为可以如下模拟:
| |
ISAAC PRNG
IsaacRng 和 Isaac64Rng PRNG 现在有额外的构造方法:new_from_u64(seed)。64 位状态不足以用于密码学,但可能对模拟和游戏有用。未来可能会被从任何可哈希对象构造任何 PRNG 的方法取代。
HC-128
这是新的密码学生成器,被 eSTREAM 选为「适合广泛采用的流密码」之一。这现在是默认密码学生成器,由 StdRng 和 thread_rng() 使用。
辅助函数/trait
Rand trait 已被弃用。相反,鼓励用户使用 Standard,它是真正的分布并支持与 Rand 相同的采样。Rng::gen() 现在使用 Standard,应与之前完全一样工作。有关如何为用户类型 T 实现 Distribution<T> 的 Standard,请参阅 distributions 模块文档。
weak_rng() 已被弃用;改用 SmallRng::from_entropy()。
分布
Sample 和 IndependentSample trait 已被单一 trait Distribution 替换。这大致等价于 IndependentSample,但 ind_sample 被替换为 sample。对可变分布的支持已被移除;虽然似乎可能有少数真正的用途,但这些用途不够广泛,无法证明存在两个独立 trait 或必须提供对分布对象的可变访问。Sample 和 IndependentSample 仍然可用,但已弃用;它们将在未来版本中移除。
Distribution::sample(以及其他几个函数)现在可以直接在类型擦除(unsized)的 RNG 上调用。
RandSample 已被移除(参见 Rand 弃用和新 Standard 分布)。
Closed01 包装器已被移除,但 OpenClosed01 已添加。
均匀分布
两个新分布可用:
Standard为许多不同类型产生均匀分布的样本,并作为Rand的替代品Alphanumeric从a-z A-Z 0-9范围采样char
范围
Range 分布已大幅调整,并重命名为 Uniform:
Uniform::new(low, high)保留(半开[low, high))Uniform::new_inclusive(low, high)已添加,在采样范围中包含highUniform::sample_single(low, high, rng)是从[low, high)单次采样的更快变体
Uniform 现在可以为用户定义的类型实现;参见 uniform 模块。
非均匀分布
添加了两个分布:
- Poisson,建模固定时间间隔内来自恒定速率源的预期事件数(例如核衰变)
- Binomial,建模固定次数是/否试验的结果
采样方法基于《Numerical Recipes in C》中的方法。
指数分布与正态分布
主要的 Exp 和 Normal 分布未变,但「标准」版本 Exp1 和 StandardNormal 不再是包装类型,而是完整分布。不再写 let Exp1(x) = rng.gen();,而是写 let x = rng.sample(Exp1);。