Shane
Shane

Reputation: 113

Cannot move out of `*X` which is behind a shared reference when using Box

I understand the reason why this error is being raised, but not sure how I should go about fixing it. Ideally I would want to avoid using Copy.

fn get_random_samples<'a>(kmers: &[Box<str>], sample_size: usize) -> Vec<Box<str>> {
    let mut rng = rand::thread_rng();

    kmers
        .choose_multiple(&mut rng, sample_size)
        .map(|item| *item)
        .collect::<Vec<Box<str>>>()
}

This raises the compilation error:

error[E0507]: cannot move out of `*item` which is behind a shared reference
   --> src\lib.rs:384:21
    |
384 |         .map(|item| *item)
    |                     ^^^^^ move occurs because `*item` has type `Box<str>`, which does not implement the `Copy` trait

I've also tried:

fn get_random_samples<'a>(kmers: &[Box<str>], sample_size: usize) -> Vec<Box<str>> {
    let mut rng = rand::thread_rng();

    kmers
        .choose_multiple(&mut rng, sample_size)
        .copied()
        .collect::<Vec<Box<str>>>()
}

as learned from a previous question (Random sampling of a string slice), but this raises a different error:

error[E0277]: the trait bound `Box<str>: std::marker::Copy` is not satisfied
    --> src\lib.rs:384:10
     |
384  |         .copied()
     |          ^^^^^^ the trait `std::marker::Copy` is not implemented for `Box<str>`
     |
note: required by a bound in `std::iter::Iterator::copied`
    --> C:\Users\shant\.rustup\toolchains\nightly-x86_64-pc-windows-msvc\lib/rustlib/src/rust\library\core\src\iter\traits\iterator.rs:2987:12
     |
2987 |         T: Copy,
     |            ^^^^ required by this bound in `std::iter::Iterator::copied`

Both errors seem to point to the Copy trait which ideally I would like to avoid.

Any help would be appreciated!.

PS: Quite new to Rust, please do suggest if there's better ways to do this.

Upvotes: 2

Views: 2017

Answers (1)

Netwave
Netwave

Reputation: 42756

If you want to avoid copying/cloning, you need to return a reference. For example:

use rand::prelude::SliceRandom;
fn get_random_samples(kmers: &[Box<str>], sample_size: usize) -> Vec<&Box<str>> {
    let mut rng = rand::thread_rng();

    kmers
        .choose_multiple(&mut rng, sample_size)
        .collect()
}

Playground

or:

use rand::prelude::SliceRandom;
fn get_random_samples(kmers: &[Box<str>], sample_size: usize) -> Vec<&str> {
    let mut rng = rand::thread_rng();

    kmers.choose_multiple(&mut rng, sample_size).map(|e| e as &str).collect()
}

Playground

Upvotes: 1

Related Questions