I'm trying to compute the 10,001st prime in Rust (Project Euler 7), and as a part of this, my method to check whether or not an integer is prime references a vector. However, when I try to reference the vector, I get the following error:
error: use of moved value: `primes`
note: `primes` was previously moved here because it has type `collections::vec::Vec<u64>`, which is non-copyable
error: use of moved value: `primes`
error: aborting due to 2 previous errors
My source code is below:
fn main(){
let mut count: u32 = 1;
let mut num: u64 = 1;
let mut primes: Vec<u64> = Vec::new();
primes.push(2);
while count < 10001{
num += 2;
if vectorIsPrime(num, primes){
count+=1;
primes.push(num);
}
}
}
fn vectorIsPrime(num: u64, p: Vec<u64>) -> bool{
for i in p{
if num > i && num % i != 0{
return false;
}
}
true
}
What do I have to do to primes
in order to be able to access it within the vectorIsPrime
function?
Rust is, as I would say, a “value-oriented” language. This means that if you define primes like this
it is not a reference to a vector. It is practically a variable that stores a value of type
Vec<u64>
just like anyu64
variable stores au64
value. This means that if you pass it to a function defined like thisthe function will get its own
u64
value and its ownVec<u64>
value.The difference between
u64
andVec<u64>
however is that au64
value can be easily copied to another place while aVec<u64>
value can only move to another place easily. If you want to give thevec_is_prime
function its ownVec<u64>
value while keeping one for yourself in main, you have to duplicate it, somehow. That's what'sclone()
is for. The reason you have to be explicit here is because this operation is not cheap. That's one nice thing about Rust: It's not hard to spot expensive operations. So, you could call the function like thisbut that's not really what you want, actually. The function does not need its own a
Vec<64>
value. It just needs to borrow it for a short while. Borrowing is much more efficient and applicable in this case:Invoking it now requires the “borrowing operator”:
Much better. But we can still improve it. If a function wants to borrow a
Vec<T>
just for the purpose of reading it, it's better to take a&[T]
instead:It's just more general. Now, you can lend a certain portion of a Vec to the function or something else entirely (not necessarily a
Vec
, as long as this something stores its values consecutively in memory, like a static lookup table). What's also nice is that due to coersion rules you don't need to alter anything at the call site. You can still call this function with&primes
as argument.For
String
and&str
the situation is the same.String
is for storing string values in the sense that a variable of this type owns that value.&str
is for borrowing them.You move value of
primes
to the functionvectorIsPrime
(BTW Rust usesnake_case
by convention). You have other options, but the best one is to borrow vector instead of moving it:And then passing reference to it:
With the current definition of your function
vectorIsPrime()
, the function specifies that it requires ownership of the parameter because you pass it by value.When a function requires a parameter by value, the compiler will check if the value can be copied by checking if it implements the trait
Copy
.That is the meaning of the error message you have.
However, most functions do not require ownership of the parameters: they can work on "borrowed references", which means they do not actually own the value (and cannot for example put it in a container or destroy it).
The function
vector_is_prime()
now specifies that it only needs a slice, i.e. a borrowed pointer to an array (including its size) that you can obtain from a vector using the borrow operator & (this is recent in Rust, you may still find examples where a method .as_slice() is called explicitly)For more information about ownership, I invite you to read the part of the book dealing with ownership.