Search code examples
rustrandominitialization

How to initialise a 16-byte array with a random value?


I need to intialise a 16-byte array with a random value (not a Vec or a slice).

I'm currently using:

let mut rng = rand::thread_rng();
let mut foo = [0u8; 16]; 
rng.fill(&mut foo);
let foo = foo; // discard mutability

but this seems needlessly verbose, and writes the array twice (first, initialising with zeros, then, writing random values).

Can I initialise an array to a random value, rather than initialising it to zeros and updating it to a random value?


Solution

  • Two ways come to my mind.

    • Use rnd.gen() directly. According to its documentation it can generate arrays with up to 32 elements directly. (Note that rand has a feature called min_const_gen that removes this restriction, but requires Rust 1.51 or newer. Which should be fine in almost all cases)
    • Generate a [(); N] (which is a zero-cost abstraction, as it is a zero-sized type) and .map() it to its desired value. This can be done with arbitrarily large arrays.
    use rand::Rng;
    
    fn main() {
        let mut rng = rand::thread_rng();
    
        let foo1: [u8; 16] = rng.gen();
        let foo2: [u8; 16] = [(); 16].map(|()| rng.gen());
    
        println!("{:?}", foo1);
        println!("{:?}", foo2);
    }
    
    [202, 93, 254, 143, 106, 93, 194, 80, 141, 108, 119, 155, 125, 85, 84, 205]
    [24, 237, 188, 0, 6, 240, 228, 117, 41, 253, 29, 148, 246, 47, 96, 181]
    

    But be aware of the quote from Rng::gen()'s documentation:

    For arrays of integers, especially for those with small element types (< 64 bit), it will likely be faster to instead use Rng::fill.

    So while gen() is technically more concise and only writes to the array once, it might also be less efficient. But if this is relevant for you, don't take my word and instead benchmark it yourself.