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的副本是否更好?如果返回副本,请不要担心借用检查器,因为您没有从结构中借用任何内容。作为参考,这里是最终的保管器: