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

时间:2018-03-07 20:11:26

标签: 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);
    }
}

错误消息是:

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

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

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

1 个答案:

答案 0 :(得分: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);
    }
}

这打印出你想要的数字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} {1}})。

我已经解释了为什么你不能拥有自己\s*的副本。

相关问题