Как мне создать Vec из диапазона и перетасовать его?

У меня есть следующий код:

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

и получите следующую ошибку:

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]`

Кажется, я понимаю, что содержимое векторов и срезов неизменно, и это вызывает здесь ошибку, но я не уверен.

Подпись as_mut_slicepub fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T], поэтому срез должен быть изменяемым, но почему-то это не так.

Я знаю, что должно быть простое решение, но я старался изо всех сил и не смог заставить его работать.


person le_me    schedule 25.09.2014    source источник


Ответы (2)


Ранд v0.6.0

Метод Rng::shuffle теперь устарел; Следует использовать черту rand::seq::SliceRandom. Он предоставляет метод shuffle() для всех слайсов, который принимает экземпляр Rng:

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

См. в Playground.

Оригинальный ответ

Вы очень близко. Это должно работать:

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] неявно приводится к &[T], а вы аннотировали переменную slice с помощью &[u32], поэтому срез стал неизменяемым: &mut [u32] был приведен к &[u32]. mut для переменной здесь не имеет значения, потому что слайсы просто заимствуются в данные, принадлежащие кому-то другому, поэтому они не имеют унаследованной изменчивости — их изменчивость закодирована в их типах.

На самом деле вам вообще не нужна аннотация к slice. Это также работает:

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

Вам даже не нужна промежуточная переменная:

extern crate rand;

use rand::{thread_rng, Rng};

fn main() {
    let mut vec: Vec<u32> = (0..10).collect();
    thread_rng().shuffle(&mut vec);
}

Вам следует прочитать Язык программирования Rust поскольку он объясняет концепции владения и заимствования и то, как они взаимодействуют с изменчивостью.


person Vladimir Matveev    schedule 25.09.2014
comment
Спасибо за ваш ответ. К сожалению, я вставил ваш код в Rust Playground (play.rust-lang.org) и обнаружил что thread_rng().shuffle теперь устарело. Вы знаете, как мы теперь должны перетасовать вектор? (Я думаю, что мы должны использовать трейт, но я недостаточно опытен в Rust, чтобы знать, как это сделать.) - person J-L; 11.01.2019

Вы можете использовать shuffle следующим образом:

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);
}
person Akavall    schedule 29.12.2015
comment
Спасибо за ваш ответ. К сожалению, я вставил ваш код в Rust Playground (play.rust-lang.org) и обнаружил что thread_rng().shuffle теперь устарело. Вы знаете, как мы теперь должны перетасовать вектор? (Я думаю, что мы должны использовать трейт, но я недостаточно опытен в Rust, чтобы знать, как это сделать.) - person J-L; 11.01.2019
comment
@ Джей-Л, понятно. Спасибо. Я попытался сделать это по-другому: play.rust-lang. org/, но я получаю разные предупреждения, не уверен, что это лучшее решение. - person Akavall; 11.01.2019