Search code examples
rustrandom

Random function does not return random values


If I generate 10 random numbers this way, it works (it produces different values)

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));
    }

But if I factor them into a struct, the generated values are always the same:

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());
    }
}

What is the difference between those two ways to use the get_random API, and why does it break when I put rng in a struct?


Solution

  • This doesn't work because you are copying rng out of the struct, then mutating it (registering that you have sampled a number):

    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
        }
    }
    

    Instead, you must take a mutable borrow to self to be able to mutate rng in place:

    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
        }
    }
    

    Or, more shortly

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

    Or even

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