Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rust use of moved value

Tags:

rust

When using below function:

fn factors(number: &BigInt) -> Vec<BigInt> {
    let mut n = number.clone();
    let mut i: BigInt = ToBigInt::to_bigint(&2).unwrap();
    let mut factors = Vec::<BigInt>::new();

    while i * i <= n {
        if (n % i) == ToBigInt::to_bigint(&1).unwrap() {
            i = i + ToBigInt::to_bigint(&1).unwrap();
        }
        else {
            n = n/i as BigInt;
            factors.push(i);
        }
        i = i + ToBigInt::to_bigint(&1).unwrap();
    }
    if n > i {
        factors.push(n);
    }
    factors
}

I get moved value errors for literally every time i or n is used, starting from the line with while, also in the if. I have read about borrowing, which I understand decently, but this thing I don't understand. I am not "copying" the value at all, so I don't see anywhere were I could lose ownership of the variables.

like image 787
Epse Avatar asked Jun 14 '16 15:06

Epse


2 Answers

Mul (and the other arithmetic operators) take the parameters by value, so i * i move the value i (this is not a problem for primitive numbers because they implement Copy - BigInt does not).

As Mul is implemented for (two) &BigInt, you can do the multiplication (and the other arithmetic operations) with &:

use num::*;

fn factors(number: &BigInt) -> Vec<BigInt> {
    let mut n = number.clone();
    let mut i = BigInt::from(2);
    let mut factors = Vec::new();

    while &i * &i <= n {
        if (&n % &i) == BigInt::one() {
            i = i + BigInt::one();

        } else {
            n = n / &i;
            factors.push(i.clone());
        }
        i = i + BigInt::one();
    }
    if n > i {
        factors.push(n);
    }
    factors
}

Note that I also made some simplifications, like omitting the type on Vec::new and using BigInt::from (cannot fail).

like image 171
malbarbo Avatar answered Sep 21 '22 03:09

malbarbo


Remember that operators in Rust are just syntactic sugar for function calls.

a + b translates to a.add(b).

Primitive types such as i32 implement the trait Copy. Thus, they can be copied into such an add function and do not need to be moved.

I assume the BigInt type you are working with does not implement this trait. Therefore, in every binary operation you are moving the values.

like image 28
JDemler Avatar answered Sep 21 '22 03:09

JDemler