14

I am writing a very simple recursive program for finding all prime numbers between two numbers:

use std::cmp::PartialOrd;
use std::ops::{Add, Div, Rem, Sub};

fn _is_prime<T>(n: T, dividend: T, one: T) -> bool
where
    T: Copy + Rem<Output = T> + Sub<Output = T> + PartialOrd,
{
    if dividend == one {
        true
    } else {
        if n % dividend < one {
            false
        } else {
            _is_prime(n, dividend - one, one)
        }
    }
}

fn _primes_between<'a, T>(a: T, b: T, one: T, v: &'a mut Vec<T>) -> &'a mut Vec<T>
where
    T: Copy + Rem<Output = T> + Add<Output = T> + Sub<Output = T> + PartialOrd,
{
    if a <= b {
        if _is_prime(a, a - one, one) {
            v.push(a);
        }

        _primes_between(a + one, b, one, v)
    } else {
        v
    }
}

fn primes_between<T>(a: T, b: T) -> Vec<T>
where
    T: Copy + Div<Output = T> + Rem<Output = T> + Add<Output = T> + Sub<Output = T> + PartialOrd,
{
    let one = a / a;

    let mut v: Vec<T> = Vec::new();

    *_primes_between(a, b, one, &mut v)
}

fn main() {
    primes_between(3, 13).iter().for_each(|i| println!("{}", i));
}

The problem is:

error[E0507]: cannot move out of a mutable reference
  --> src/main.rs:42:5
   |
42 |     *_primes_between(a, b, one, &mut v)
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move occurs because value has type `std::vec::Vec<T>`, which does not implement the `Copy` trait

How do I solve that error?

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Abner Gomes de Sá
  • 143
  • 1
  • 1
  • 4
  • 8
    Not related to your question, but in Rust the `_` prefix is not necessary for privacy because there is the `pub` keyword, and so it has acquired the meaning of "unused". A seasoned Rustacean wouldn't name functions things like `_primes_between` and `_is_prime`. Besides using `pub`, another thing you can do to limit visibility is declare functions inside other functions, if they are not used elsewhere. – trent Oct 17 '20 at 01:38

1 Answers1

9

I'm not 100% sure, but I think the problem is that _primes_between() returns a reference that the code on line 31 is trying to make a copy of. (by taking ownership with the * operator) You could fix the problem by calling .clone() on the result, but I think in this case you don't need _primes_between() to return a value - you can just add the appropriate entries to the v parameter instead. Something like

fn _primes_between<T>(a: T, b: T, one: T, v: &mut Vec<T>)
where
    T: Copy + Rem<Output = T> + Add<Output = T> + Sub<Output = T> + PartialOrd,
{
    if a <= b {
        if _is_prime(a, a - one, one) {
            v.push(a);
        }

        _primes_between(a + one, b, one, v);
    }
}

fn primes_between<T>(a: T, b: T) -> Vec<T>
where
    T: Copy + Div<Output = T> + Rem<Output = T> + Add<Output = T> + Sub<Output = T> + PartialOrd,
{
    let one = a / a;

    let mut v: Vec<T> = Vec::new();

    _primes_between(a, b, one, &mut v);

    v
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
gregstoll
  • 1,318
  • 9
  • 14
  • Thank you! So, if the return is a Vec, it is always be a "clone" (deep copy)? – Abner Gomes de Sá Oct 17 '20 at 01:26
  • 1
    There is no clone or deep copy here. `_primes_between` grows `v` in place and it is moved out of the function when `primes_between` returns. – trent Oct 17 '20 at 01:51
  • 1
    To be clear, Rust generally doesn't deep copy things automatically. To do that, you have to call `clone()` on a struct that implements the `Clone` trait. – gregstoll Oct 17 '20 at 02:48