为什么在可变引用上调用方法涉及“借用”?

时间:2015-01-05 22:56:44

标签: rust

我正在学习Rust,我正试图将这段代码编译成编译:

use std::vec::Vec;
use std::collections::BTreeMap;

struct Occ {
    docnum: u64,
    weight: f32,
}

struct PostWriter<'a> {
    bytes: Vec<u8>,
    occurrences: BTreeMap<&'a [u8], Vec<Occ>>,
}

impl<'a> PostWriter<'a> {
    fn new() -> PostWriter<'a> {
        PostWriter {
            bytes: Vec::new(),
            occurrences: BTreeMap::new(),
        }
    }

    fn add_occurrence(&'a mut self, term: &[u8], occ: Occ) {
        let occurrences = &mut self.occurrences;
        match occurrences.get_mut(term) {
            Some(x) => x.push(occ),
            None => {
                // Add the term bytes to the big vector of all terms
                let termstart = self.bytes.len();
                self.bytes.extend(term);
                // Create a new occurrences vector
                let occs = vec![occ];
                // Take the appended term as a slice to use as a key
                // ERROR: cannot borrow `*occurrences` as mutable more than once at a time
                occurrences.insert(&self.bytes[termstart..], occs);
            }
        }
    }
}

fn main() {}

我收到错误:

error[E0499]: cannot borrow `*occurrences` as mutable more than once at a time
  --> src/main.rs:34:17
   |
24 |         match occurrences.get_mut(term) {
   |               ----------- first mutable borrow occurs here
...
34 |                 occurrences.insert(&self.bytes[termstart..], occs);
   |                 ^^^^^^^^^^^ second mutable borrow occurs here
35 |             }
36 |         }
   |         - first borrow ends here

我不明白......我只是在一个可变引用上调用一个方法,为什么这行涉及借用?

2 个答案:

答案 0 :(得分:9)

  

我只是在一个可变引用上调用一个方法,为什么该行涉及借用?

当您在某个对象上调用某个方法来改变该对象时,您无法该对象的任何其他引用。如果您这样做,您的突变可能会使这些引用无效并使您的程序处于不一致状态。例如,假设您从hashmap中获取了一个值,然后添加了一个新值。添加新值会达到魔法限制并强制重新分配内存,您的值现在无处可寻!当你使用那个价值时... bang就是程序!

在这种情况下,看起来你想做相对常见的&#34;追加或插入,如果遗漏&#34;操作。您需要使用entry

use std::collections::BTreeMap;

fn main() {
    let mut map = BTreeMap::new();

    {
        let nicknames = map.entry("joe").or_insert(Vec::new());
        nicknames.push("shmoe");

        // Using scoping to indicate that we are done with borrowing `nicknames`
        // If we didn't, then we couldn't borrow map as
        // immutable because we could still change it via `nicknames`
    }

    println!("{:?}", map)
}

答案 1 :(得分:1)

因为你正在调用一个借用可变的方法

我昨天有一个关于Hash的类似问题,直到我注意到文档中的某些内容。 The docs for BTreeMap显示以insert

开头的fn insert(&mut self..的方法签名

所以当你调用.insert时,你隐含地要求该函数将BTreeMap借用为可变的。