Search code examples
iteratorimmutabilityrustmutability

How do I create a Vec from a range and shuffle it?


I have the following code:

extern crate rand;

use rand::{thread_rng, Rng};

fn main() {
    let mut vec: Vec<u32> = (0..10).collect();
    let mut slice: &[u32] = vec.as_mut_slice();

    thread_rng().shuffle(slice);
}

and get the following error:

error[E0308]: mismatched types
 --> src/main.rs:9:26
  |
9 |     thread_rng().shuffle(slice);
  |                          ^^^^^ types differ in mutability
  |
  = note: expected type `&mut [_]`
             found type `&[u32]`

I think I understand that the content of vectors and slices is immutable and that causes the error here, but I'm unsure.

The signature of as_mut_slice is pub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T], so the slice should be mutable, but it somehow isn't.

I know that there must be an easy fix, but I tried my best and couldn't get it to work.


Solution

  • Rand v0.6.0

    The Rng::shuffle method is now deprecated; rand::seq::SliceRandom trait should be used. It provides the shuffle() method on all slices, which accepts an Rng instance:

    // Rust edition 2018 no longer needs extern crate
    
    use rand::thread_rng;
    use rand::seq::SliceRandom;
    
    fn main() {
        let mut vec: Vec<u32> = (0..10).collect();
        vec.shuffle(&mut thread_rng());
        println!("{:?}", vec);
    }
    

    See it on Playground.

    Original answer

    You're very close. This should work:

    extern crate rand;
    
    use rand::{thread_rng, Rng};
    
    fn main() {
        let mut vec: Vec<u32> = (0..10).collect();
        let slice: &mut [u32] = &mut vec;
    
        thread_rng().shuffle(slice);
    }
    

    &mut [T] is implicitly coercible to &[T], and you annotated the slice variable with &[u32], so the slice became immutable: &mut [u32] was coerced to &[u32]. mut on the variable is not relevant here because slices are just borrows into data owned by someone else, so they do not have inherited mutability - their mutability is encoded in their types.

    In fact, you don't need an annotation on slice at all. This works as well:

    extern crate rand;
    
    use rand::{thread_rng, Rng};
    
    fn main() {
        let mut vec: Vec<u32> = (0..10).collect();
        let slice = vec.as_mut_slice();
    
        thread_rng().shuffle(slice);
    }
    

    You don't even need the intermediate variable:

    extern crate rand;
    
    use rand::{thread_rng, Rng};
    
    fn main() {
        let mut vec: Vec<u32> = (0..10).collect();
        thread_rng().shuffle(&mut vec);
    }
    

    You should read The Rust Programming Language as it explains the concepts of ownership and borrowing and how they interact with mutability.