随机函数不会返回随机值

4
如果我用这种方法生成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());
    }
}

这两种使用get_random API的方式有什么区别,为什么当我将rng放入一个结构体中时会出错?
1个回答

9

这不起作用,因为你从结构体中复制了 rng,然后对其进行了变异(注册你已经抽样了一个数字):

impl Util {
    pub fn get_random(&self) -> u32 {
        let mut rng = self.rng;  // <-- here you copy `rng`,
                                 // creating a new value, unrelated with `self.rng`
        let random_number = rng.rand_range(0..4); // <-- here you mutate `rng`,
        random_number                             // but leave `self.rng` untouched
    }
}

相反,你必须对 `self` 进行可变借用,以便能够直接修改 `rng`。
impl Util {
    pub fn get_random(&mut self) -> u32 {
        //             +++ `mut` has been added, to allow mutation of `self`
        let rng = &mut self.rng;  // this does not copy `self.rng`
        let random_number = rng.rand_range(0..4);
        random_number
    }
}

或者更简洁地说

impl Util {
    pub fn get_random(&mut self) -> u32 {
        let random_number = self.rng.rand_range(0..4);
        random_number
    }
}

甚至更好
impl Util {
    pub fn get_random(&mut self) -> u32 {
        self.rng.rand_range(0..4)
    }
}

谢谢你帮我解决这个困惑! - Magin
3
这就是为什么(与官方Rust建议相反)我不是一个对每个可以接受的结构体都强烈推荐使用#[derive(Copy)]的粉丝的原因... - Finomnis
1
@Finomnis是的,我一开始也很惊讶,你竟然能复制这个携带非平凡内部状态的不透明结构。如果对于每种合格类型Copy不是自动特质,那正是因为存在这样的情况,实现它是没有意义的。 - jthulhu
另外,oorandom 没有适当的贡献方式(没有 GitHub),它有未解决的错误报告(https://todo.sr.ht/~icefox/oorandom/7),甚至没有实现 rand_core(https://docs.rs/rand_core/)。@Magin 我认为通常应该用 rand_pcg 替代它。我不明白为什么 oorandom 变得这么大,但在我看来,它并不值得如此。也许是因为它有一个漂亮的主页。 - Finomnis
谢谢 @Finomnis!我也很好奇为什么在谷歌上找不到更多关于oorandom的信息。我会在我的项目中尝试使用rand_pcg - Magin
1
@Magin 这个问题稍微有点复杂,因为它使用了 rand_core 特性来保持一致性,这意味着一些功能需要 RandCoreSeedableRng 特性。但是,你可以使用例如 Pcg32::seed_from_u64 来初始化它,并使用所有的 RandCore 函数来获取随机性。 - Finomnis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接