为什么函数调用顺序会影响借用?

时间:2017-07-05 12:15:49

标签: rust

为什么在这种情况下我需要强制借用范围?没有它,k.keep("X")将导致编译错误。

mod keep {
    use std::collections::hash_map::Entry::{Occupied, Vacant};
    use std::collections::HashMap;
    use std::hash::Hash;

    pub struct Keeper<T> {
        index:  Vec<T>,
        kept:   HashMap<T, usize>
    }
    impl<T> Keeper<T> {
        pub fn new() -> Keeper<T> where T: Eq + Hash {
            Keeper { index: Vec::new(), kept: HashMap::new() }
        }
        pub fn keep(&mut self, keepsake: T) -> usize where T: Eq + Hash + Copy {
            match self.kept.entry(keepsake) {
                Occupied(_)   => (),
                Vacant(entry) => {
                    entry.insert(self.index.len());
                    self.index.push(keepsake);
                }
            }
            *self.kept.get(&keepsake).unwrap()
        }
        pub fn find(&self, i:usize) -> &T {
            &self.index[i]
        }
    }
}
fn main() {
    let mut k: keep::Keeper<&str> = keep::Keeper::new();
    { // forced borrow scoping
        let (k1, k2, k3) = (k.keep("A"), k.keep("A"), k.keep("B"));
        println!("{}@[{:p}], {}@[{:p}], {}@[{:p}]", k1, &k1, k2, &k2, k3, &k3);
        let (s1, s2, s3) = (k.find(k1), k.find(k2), k.find(k3));
        println!("{}@[{:p}], {}@[{:p}], {}@[{:p}]", s1, s1, s2, s2, s3, s3);
    }
    let k4 = k.keep("X");
}

a playground

2 个答案:

答案 0 :(得分:1)

这是一个非常简单的案例;在以下绑定中:

let (s1, s2, s3) = (k.find(k1), k.find(k2), k.find(k3));

你不可避免地借用k 3次(你可以有多次不可变借用),所以只要s1s2s3在范围内,你就可以不要随意借用k

通过引入自己的范围,您s1s2s3会在其阻止结束时释放借款。

答案 1 :(得分:1)

最小复制:

struct Foo {
    something: i32,
}

impl Foo {
    fn give_something(&self) -> &i32 {
        &self.something
    }
    fn bar(&mut self) {}
}

fn main() {
    let mut foo = Foo{ something: 42, };
    // In the following line, you borrow self.something with thing,
    // therefore, foo is borrowed too:
    let thing = foo.give_something();
    // Then you cannot mutably borrow foo since it is already borrowed:
    foo.bar();
}

所有都在编译器的解释中:

  

不能将foo借用为可变的,因为它也被借用为不可变的

你可以在一个东西上有一个可变的引用,或者有多个不可变的引用,而不是两个。

现在在您的代码中看到:您首先借用k作为不可变的:

let (s1, s2, s3) = (k.find(k1), k.find(k2), k.find(k3));

然后你要求借用它是可变的:

let k4 = k.keep("X");