【问题标题】:Understanding for loop semantics when iterating through a vector containing mutable references在迭代包含可变引用的向量时理解 for 循环语义
【发布时间】:2018-03-07 20:11:26
【问题描述】:

我试图理解为什么下面的代码会失败:

fn main() {
    let mut a = 10;
    let mut b = 20;
    let mut c = 30;
    let p = vec![&mut a, &mut b, &mut c]; // works with [&a, &b, &c]

    for &x in &p { // works with 'x' instead of of '&x'
        println!("{}", x);
    }
}

错误信息是:

error[E0507]: cannot move out of borrowed content
 --> src/main.rs:7:9
  |
7 |     for &x in &p {
  |         ^-
  |         ||
  |         |hint: to prevent move, use `ref x` or `ref mut x`
  |         cannot move out of borrowed content

据我了解,“借用内容”是vec! 对变量abc 的可变引用,但究竟是什么在这里“移动”了?我认为移动发生在for 循环的开头。

我认为有两个可变引用(一个来自vec),但我想我无法正确解构&x,我知道答案就在那里。如果我按照编译器的建议将ref x 放在那里或使用&&mut x,我能够理解它为什么会起作用,但我不理解上述情况。 (即&x)。

【问题讨论】:

    标签: reference rust


    【解决方案1】:

    这有点棘手,因为 Rust 中的绑定可能有点棘手,但首先让我们看看我们正在处理什么,并从一些可以编译的代码开始:

    fn main() {
        let mut a = 10;
        let mut b = 20;
        let mut c = 30;
        let p = vec![&mut a, &mut b, &mut c];
    
        for x in &p {              // note the lack of &x
            println!("{}", x);
        }
    }
    

    这会像您期望的那样打印出数字 10、20、30,但为什么呢?让我们更改代码以获得一个错误,它将告诉我们x 是什么:

    for x in &p {              // note the lack of &x
        x + ();
    }
    

    然后你会看到error[E0369]: binary operation + cannot be applied to type &&mut {integer}

    迭代&p 得到的是对整数的可变引用的引用。具体来说,您将获得对向量拥有的对整数的可变引用的引用。循环无法获得该可变引用的副本,因为有两个未完成的可变引用是禁忌。如果您不将该可变引用移出向量,则 for 循环将不得不满足于对该可变引用进行不可变借用。这里有一些代码可以证明我在说什么:

    let borrow = &p[0];
    assert_eq!(borrow, &&mut 10);
    
    // Try to get our own `&mut 10` out of `borrow`    
    let gimme = *borrow; // error[E0507]: cannot move out of borrowed content
    

    现在让我们谈谈for &x in &p 的作用。这里有两个等效循环,它们给你相同的x,也给你同样的错误。

    for &x in &p {           
    }
    
    for temp in &p {
        let x = *temp;
    } 
    

    这是因为for &x in ... 是一个解构绑定。您断言“&x 与迭代 &p 的项目的结构相匹配。我希望 x 成为该匹配的一部分,而没有第一个 &。”

    类似这样:

    let borrow = &p[0];
    assert_eq!(borrow, &&mut 10);
    
    // Try to get our own `&mut 10` out of `borrow`    
    let gimme = *borrow; // error[E0507]: cannot move out of borrowed content    
    let &gimme_gimme = borrow;  // error[E0507]: cannot move out of borrowed content
    

    在这种情况下,&x 匹配 &&mut {integer},其中 & 匹配第一个 &x,然后绑定到剩下的 (&mut {integer})。

    我已经解释了为什么你不能拥有自己的 &mut {integer} 副本。

    【讨论】:

      猜你喜欢
      • 2018-05-31
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      • 2014-11-21
      • 2020-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多