You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 22:36:35