从中索引后添加到向量

时间:2021-07-27 23:40:16

标签: rust

我对这里的这个例子很好奇https://doc.rust-lang.org/book/ch08-01-vectors.html

$ cargo run
   Compiling collections v0.1.0 (file:///projects/collections)
error[E0502]: cannot borrow `v` as mutable because it is also borrowed as immutable
 --> src/main.rs:6:5
  |
4 |     let first = &v[0];
  |                  - immutable borrow occurs here
5 | 
6 |     v.push(6);
  |     ^^^^^^^^^ mutable borrow occurs here
7 | 
8 |     println!("The first element is: {}", first);
  |                                          ----- immutable borrow later used here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0502`.
error: could not compile `collections`

To learn more, run the command again with --verbose.

在高层次上,对 v 中的项目的引用与对 v 本身的引用有何相同之处。这在语法上是如何执行的? 如何简单地实现带有示例类型的东西来举例说明这一点?到目前为止我能找到的只是所有权阻止了这种情况,但我找不到任何可以解释它的内幕。

感谢任何帮助!

1 个答案:

答案 0 :(得分:3)

如果向量需要调整大小以容纳附加项,则必须分配新内存并将所有现有项移动到新分配中。这会破坏未完成的引用,这就是不允许的原因。其他形式的突变可能类似地破坏引用 - 例如删除一个项目可能会删除被引用的项目或导致它在向量内移动。

这是由 Rust 中的生命周期和引用的工作方式强制执行的。 Vec 实现了 Index trait 以提供 [] 运算符,该运算符的方法签名为 fn index(&self, index: Idx) -> &Self::Output。请注意 self 是如何被不可变引用 (&) 获取的,并且该函数还返回一个不可变引用。由于没有为这些引用明确指定生命周期,编译器推断它们是链接的——即,返回的引用仅在对容器本身的引用有效时才有效。

接下来,您尝试使用 push 对向量进行变异。这具有签名 fn push(&mut self, value: T)。请注意,此函数通过 mutable 引用 (self) 获取 &mut,这要求没有其他对向量的引用。由于编译器在上一步中发现索引向量会返回一个与向量本身相关的引用,因此它不允许我们调用 push

你可以用这样的代码很容易地创建一个类似的例子:

struct MyStruct {
    a: i32
}

impl MyStruct {
    fn get_a(&self) -> &i32 {
        &self.a
    }
    
    fn set_a(&mut self, value: i32) {
        self.a = value;
    }
}

fn main() {
    let mut thing = MyStruct { a: 5 };
    let reference = thing.get_a();
    thing.set_a(10); // error! thing is already borrowed due to get_a()
    println!("Value: {}", reference);
}

Rust 书在几个地方讨论了这些主题。我建议通读References and BorrowsValidating references with lifetimes

相关问题