为何将Rand32放入结构体后,随机函数无法生成不同值?
随机数生成封装到结构体后值重复的问题分析
我通过以下代码可以正常生成10个不同的随机数:
fn main() { let seed = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .expect("system time cannot be before unix epoch") .as_millis() as u64; let mut rng = oorandom::Rand32::new(seed); for _ in 0..10 { println!("Your random number is: {}", &rng.rand_range(0..4)); } }
但将其封装到结构体后,生成的值始终相同:
use oorandom::{self, Rand32}; struct Util { rng: Rand32, } impl Util { pub fn new() -> Self { let seed = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_millis() as u64; println!("new color util {}", seed); let rng = Rand32::new(seed); Util { rng } } pub fn get_random(&self) -> u32 { let mut rng = self.rng; let random_number = rng.rand_range(0..4); random_number } } fn main() { let util = Util::new(); for _ in 0..10 { println!("Your random number is: {}", util.get_random()); } }
两种用法的核心差异与问题原因
1. 第一个示例的正确逻辑
Rand32是带内部状态的随机数生成器——每次调用rand_range这类方法,都会修改自身内部的状态值,这样下一次调用就能基于新状态生成不同的随机数。
第一个示例中,我们声明了mut rng,允许修改这个生成器的状态,循环中反复调用它的方法,自然会得到不同的结果。
2. 结构体封装后的错误点
问题出在get_random方法里的这行代码:
let mut rng = self.rng;
因为Rand32实现了Copy trait,这行代码并不是拿到原生成器的引用,而是直接拷贝了一份和原生成器状态完全相同的副本。每次调用get_random,都相当于从头创建一个初始状态的生成器,调用rand_range只会修改这个临时副本的状态,结构体里保存的原生成器状态根本没变。循环10次就相当于用同一个初始状态生成10次随机数,结果必然重复。
修复方法
要让方法修改结构体内部的生成器状态,需要把方法的接收者改为&mut self,直接操作内部的rng:
impl Util { // new方法保持不变 pub fn new() -> Self { let seed = std::time::SystemTime::now() .duration_since(std::time::UNIX_EPOCH) .unwrap() .as_millis() as u64; println!("new color util {}", seed); let rng = Rand32::new(seed); Util { rng } } // 修改接收者为&mut self,直接操作内部rng pub fn get_random(&mut self) -> u32 { self.rng.rand_range(0..4) } } fn main() { // 这里也要把util声明为mut let mut util = Util::new(); for _ in 0..10 { println!("Your random number is: {}", util.get_random()); } }
这样每次调用get_random都会更新结构体内部rng的状态,后续调用就能生成新的随机值了。
内容的提问来源于stack exchange,提问作者Magin
相关产品推荐
相关产品推荐

