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

36,424

Solution 1

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.


Solution 2

You can use shuffle like this:

extern crate rand;

use rand::Rng;

fn main() {
    let mut vec: Vec<usize> = (0..10).collect();
    println!("{:?}", vec);
    rand::thread_rng().shuffle(&mut vec);
    println!("{:?}", vec);
}
Share:
36,424
le_me
Author by

le_me

Updated on March 26, 2020

Comments

  • le_me
    le_me about 4 years

    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.

  • J-L
    J-L over 5 years
    Thank you for your answer. Unfortunately, I pasted your code into the Rust Playground (play.rust-lang.org) and discovered that thread_rng().shuffle is now deprecated. Do you know how we're supposed to shuffle a vector now? (I think we're supposed to use a trait, but I'm not experienced enough in Rust to know how to do that yet.)
  • J-L
    J-L over 5 years
    Thank you for your answer. Unfortunately, I pasted your code into the Rust Playground (play.rust-lang.org) and discovered that thread_rng().shuffle is now deprecated. Do you know how we're supposed to shuffle a vector now? (I think we're supposed to use a trait, but I'm not experienced enough in Rust to know how to do that yet.)
  • Akavall
    Akavall over 5 years
    @J-L, I see. Thanks. I tried to do it the other way: play.rust-lang.org/…, but I am getting different warnings, not sure if this is a better solution.