在迭代包含可变引用的向量时理解循环语义

sou*_*ics 1 reference rust

我试图理解为什么以下代码失败:

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

错误消息是:

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

据我了解,在"借来的内容"是变量的可变引用a,b,cvec!,但究竟是什么让"感动"吗?我认为此举是在for循环开始时发生的.

我认为有两个可变参考(一个vec)被举行,但我想我无法&x正确解构我的理解,我知道答案就在那里.我能够理解为什么它如果我ref x按照编译器或使用的建议放入那里&&mut x,但我不理解上述情况.(即&x).

tur*_*too 5

这有点棘手,因为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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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

for x in &p {              // note the lack of &x
    x + ();
}
Run Code Online (Sandbox Code Playgroud)

然后你看 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
Run Code Online (Sandbox Code Playgroud)

现在让我们来谈谈做的事情for &x in &p.这里有两个等效的循环,它们会给你x相同的错误.

for &x in &p {           
}

for temp in &p {
    let x = *temp;
} 
Run Code Online (Sandbox Code Playgroud)

这是因为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
Run Code Online (Sandbox Code Playgroud)

在这种情况下,&x匹配&&mut {integer}其中&第一相匹配&,并x随后变为绑定到还剩下些什么(&mut {integer}).

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