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

Rust 为什么函数调用顺序会影响借用?,rust,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>, k

在这种情况下,为什么我需要强制借款范围?没有它,
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");
}
mod keep{
使用std::collections::hash_map::Entry:{占用,空闲};
使用std::collections::HashMap;
使用std::hash::hash;
酒吧结构管理员{
索引:Vec,
保存:HashMap
}
执行保管员{
pub fn new()->Keeper,其中T:Eq+Hash{
Keeper{index:Vec::new(),keeped:HashMap::new()}
}
pub fn keep(&mut self,keepsake:T)->使用其中的T:Eq+Hash+Copy{
匹配自我。保留。条目(纪念品){
已占用()=>(),
空缺(条目)=>{
entry.insert(self.index.len());
self.index.push(纪念品);
}
}
*self.keeped.get(&纪念品)。unwrap()
}
发布fn查找(&self,i:usize)->&T{
&自我索引[i]
}
}
}
fn main(){
让mut k:keep::Keeper=keep::Keeper::new();
{//强制借用范围
设(k1,k2,k3)=(k.keep(“A”)、k.keep(“A”)、k.keep(“B”);
println!(“{}@[{:p}],{}@[{:p}],{}@[{:p}]”,k1,&k1,k2,&k2,k3,&k3);
设(s1,s2,s3)=(k.find(k1),k.find(k2),k.find(k3));
println!(“{}@[{:p}],{}@[{:p}],{}@[{:p}]”,s1,s1,s2,s2,s3,s3);
}
设k4=k,保持(“X”);
}

有。

这是一个非常简单的例子;在以下约束中:

let (s1, s2, s3) = (k.find(k1), k.find(k2), k.find(k3));
您可以不可变地借用
k
3次(您可以有多个不可变借用),因此只要
s1
s2
s3
在范围内,您就不能不可变地借用
k

通过介绍您自己的范围,您使
s1
s2
s3
在其区块结束时释放借款。

最小复制:

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");

这可能会导致问题,并且保管员应该重新设计,还是这种预期行为和保管员在大多数情况下都能正常工作?这取决于您将如何使用
保管员
;在这种情况下(出于打印目的),引入一个额外的作用域是完全可以的。现在试着解决这种情况,并决定什么时候你对自己的API及其使用更有信心。因此,从可变变为不可变是可以的,因为在查找之前调用keep是可行的,但反过来不行?不,规则是如果你拥有某个事物的引用
keep
不返回任何引用。啊,既然在keep as Copy中指定了T,那么从find返回T的副本是否更好?如果返回副本,请不要担心借用检查器,因为您没有从结构中借用任何内容。作为参考,这里是最终的保管器: