使用移动的值

mjk*_*fer 36 rust

我正在尝试计算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
}
Run Code Online (Sandbox Code Playgroud)

我的源代码如下:

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
Run Code Online (Sandbox Code Playgroud)

我有什么做的,primes为了能够在内部访问它vectorIsPrime的功能?

Vae*_*den 41

使用函数的当前定义vectorIsPrime(),函数指定它需要参数的所有权,因为您按值传递它.

当函数需要按值参数时,编译器将检查是否可以通过检查它是否实现了特征来复制该值Copy.

  • 如果是,则复制该值(使用memcpy)并将其赋予该函数,您仍然可以继续使用原始值.
  • 如果没有,则将值移动到给定的函数,然后调用者不能使用它

这就是您所拥有的错误消息的含义.

但是,大多数函数不需要参数的所有权:它们可以处理"借用引用",这意味着它们实际上并不拥有该值(并且不能将其放入容器中或将其销毁).

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
}
Run Code Online (Sandbox Code Playgroud)

该函数vector_is_prime()现在指定它只需要一个切片,即一个借用的指向数组的指针(包括它的大小),你可以使用借位运算符从一个向量中获取&(这是Rust中的最新版本,你仍然可以找到一个方法的例子) .as_slice()被显式调用)

有关所有权的更多信息,我邀请您阅读本书涉及所有权的部分.

  • @mjkaufer,它表示`i'是引用,因此在循环中,i将是值,而不是引用。如果您忽略它,则进行比较时需要* i。 (2认同)

sel*_*tze 34

正如我所说,Rust是一种"以价值为导向"的语言.这意味着如果您定义这样的素数

let primes: Vec<u64> = …
Run Code Online (Sandbox Code Playgroud)

它不是对向量的引用.它实际上是一个存储类型的变量,Vec<u64>就像任何u64存储u64值的变量一样.这意味着如果将它传递给这样定义的函数

fn vec_is_prime(num: u64, vec: Vec<u64>) -> bool { … }
Run Code Online (Sandbox Code Playgroud)

该函数将获得自己的u64值和自己的Vec<u64>值.

然而,之间的区别在于u64,值可以很容易地复制到另一个地方,而值只能轻松地移动到另一个地方.如果你想给这个函数赋予它自己的值,同时在main中保留一个你自己的值,你必须以某种方式复制它.这就是为了什么.你必须在这里明确的原因是因为这个操作并不便宜.这是关于Rust的一件好事:发现昂贵的操作并不难.所以,你可以像这样调用这个函数Vec<u64>u64Vec<u64>vec_is_primeVec<u64>clone()

if vec_is_prime(num, primes.clone()) { …
Run Code Online (Sandbox Code Playgroud)

但实际上,这并不是你想要的.该函数不需要自己的Vec<64>值.它只需要借用一会儿.在这种情况下,借贷效率更高,更适用:

fn vec_is_prime(num: u64, vec: &Vec<u64>) -> bool { …
Run Code Online (Sandbox Code Playgroud)

现在调用它需要"借用运算符":

if vec_is_prime(num, &primes) { …
Run Code Online (Sandbox Code Playgroud)

好多了.但我们仍然可以改进它.如果一个函数想要Vec<T>为了阅读而借用一个函数,那么最好选择一个&[T]:

fn vec_is_prime(num: u64, vec: &[u64]) -> bool { …
Run Code Online (Sandbox Code Playgroud)

它更通用.现在,您可以将Vec的某个部分完全借给函数或其他东西(不一定是Vec,只要这个东西连续地将其值存储在内存中,就像静态查找表一样).同样好的是,由于版本规则,您不需要在呼叫站点更改任何内容.您仍然可以使用&primesas参数调用此函数.

对于String&str情况是一样的.String用于存储字符串值,因为此类型的变量拥有该值.&str借用它们.


Hau*_*eth 5

您将值移动primes到函数中vectorIsPrime(顺便说一句,Rustsnake_case按惯例使用)。您还有其他选择,但最好的选择是借用 vector 而不是移动它:

fn vector_is_prime(num: u64, p: &Vec<u64>) -> bool { … }
Run Code Online (Sandbox Code Playgroud)

然后传递对它的引用:

vector_is_prime(num, &primes)
Run Code Online (Sandbox Code Playgroud)