83

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.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
le_me
  • 3,089
  • 3
  • 26
  • 28

2 Answers2

116

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.


Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Vladimir Matveev
  • 120,085
  • 34
  • 287
  • 296
  • Thank you for your answer. Unfortunately, I pasted your code into the Rust Playground (https://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 Jan 11 '19 at 17:09
  • With rand, version 0.7.0 the `Rng::shuffle` method was removed. You are now required to use the `SliceRandom::shuffle` method. – Brooke Jackson Jan 20 '23 at 16:39
18

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);
}
Kijewski
  • 25,517
  • 12
  • 101
  • 143
Akavall
  • 82,592
  • 51
  • 207
  • 251
  • Thank you for your answer. Unfortunately, I pasted your code into the Rust Playground (https://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 Jan 11 '19 at 17:09
  • 2
    @J-L, I see. Thanks. I tried to do it the other way: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=74022e6f3a22741b98782ade77531691, but I am getting different warnings, not sure if this is a better solution. – Akavall Jan 11 '19 at 18:15
  • These two compiler warnings don't seem to make sense. - One is telling "unused variable: `rng`" which is clearly wrong, you are using rng in the call to the shuffle method. - The other is saying that the rng "variable does not need to be mutable "which is also wrong because we need a mutable reference of rng in the call to shuffle on the vec. – Brooke Jackson Jan 20 '23 at 16:15