我正在尝试计算Rust中的第10,001个素数(Project Euler 7),作为其中的一部分,我检查整数是否为素数的方法引用了一个向量:
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
}
当我尝试引用向量时,我收到以下错误:
error[E0382]: use of moved value: `primes`
--> src/main.rs:9:31
|
9 | if vectorIsPrime(num, primes) {
| ^^^^^^ value moved here, in previous iteration of loop
|
= note: move occurs because `primes` has type `std::vec::Vec<u64>`, which does not implement the `Copy` trait
为了能够在primes
函数中访问它,我需要对vectorIsPrime
做些什么?
使用函数vectorIsPrime()
的当前定义,该函数指定它需要参数的所有权,因为您按值传递它。
当函数需要按值参数时,编译器将检查是否可以通过检查它是否实现了特征Copy
来复制该值。
这就是您所拥有的错误消息的含义。
但是,大多数函数不需要参数的所有权:它们可以处理“借用引用”,这意味着它们实际上并不拥有该值(并且不能将其放入容器中或将其销毁)。
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 vector_is_prime(num, &primes) {
count += 1;
primes.push(num);
}
}
}
fn vector_is_prime(num: u64, p: &[u64]) -> bool {
for &i in p {
if num > i && num % i != 0 {
return false;
}
}
true
}
函数vector_is_prime()
现在指定它只需要一个切片,即一个借用指向数组的指针(包括它的大小),你可以使用借位运算符&
从向量中获得。
有关所有权的更多信息,我邀请您阅读本书中有关ownership的部分内容。
正如我所说,Rust是一种“以价值为导向”的语言。这意味着如果您定义这样的素数
let primes: Vec<u64> = …
它不是对向量的引用。它实际上是一个存储Vec<u64>
类型值的变量,就像任何u64
变量存储u64
值一样。这意味着如果将它传递给这样定义的函数
fn vec_is_prime(num: u64, vec: Vec<u64>) -> bool { … }
该函数将获得自己的u64
值和自己的Vec<u64>
值。
然而,u64
和Vec<u64>
之间的差异是,u64
值可以很容易地复制到另一个地方,而Vec<u64>
值只能轻易地移动到另一个地方。如果你想给vec_is_prime
函数赋予自己的Vec<u64>
值,同时在main中保留一个,你必须以某种方式复制它。这就是clone()
的用途。你必须在这里明确的原因是因为这个操作并不便宜。这是关于Rust的一件好事:发现昂贵的操作并不难。所以,你可以像这样调用这个函数
if vec_is_prime(num, primes.clone()) { …
但实际上,这并不是你想要的。该函数不需要自己的Vec<64>
值。它只需要借用一会儿。在这种情况下,借贷效率更高,更适用:
fn vec_is_prime(num: u64, vec: &Vec<u64>) -> bool { …
现在调用它需要“借用运算符”:
if vec_is_prime(num, &primes) { …
好多了。但我们仍然可以改进它。如果一个函数想要只是为了阅读它而借用Vec<T>
,那么最好采用&[T]
代替:
fn vec_is_prime(num: u64, vec: &[u64]) -> bool { …
它更通用。现在,你可以将一个Vec的某个部分完全借给函数或其他东西(不一定是Vec
,只要这个东西在内存中连续存储它的值,就像静态查找表一样)。同样好的是,由于版本规则,您不需要在呼叫站点更改任何内容。您仍然可以使用&primes
作为参数调用此函数。
对于String
和&str
,情况是一样的。 String
用于存储字符串值,因为此类型的变量拥有该值。 &str
是借用它们。
您将primes
的值移动到函数vectorIsPrime
(BTW Rust按惯例使用snake_case
)。你有其他选择,但最好的选择是借用矢量而不是移动它:
fn vector_is_prime(num: u64, p: &Vec<u64>) -> bool { … }
然后传递给它:
vector_is_prime(num, &primes)