gpt4 book ai didi

rust - 借用中间变量可绕过的错误

转载 作者:行者123 更新时间:2023-12-05 04:38:46 27 4
gpt4 key购买 nike

我正在尝试用 Rust 实现一个简单的分桶哈希表(仅供练习)。哈希表结构定义为:

pub struct BucketedHashTable<K: Hash, V> {
buckets: Vec<Bucket<K, V>>,
size: usize,
}

其中 Bucket 是我对单链接堆栈的简单实现。

在表的几乎所有方法中(putremoveget),我将获取关键所在的桶被插入(从中删除,在其中查找),所以我为此提取了一个方法:

    fn pick_bucket(&mut self, key: K) -> &mut Bucket<K, V> {
let mut hasher = DefaultHasher::new();
key.hash(&mut hasher);
let hash = hasher.finish() as usize;
let index = hash % self.buckets.len();
&mut self.buckets[index]
}

我返回对桶的引用,因为我不想将它移出哈希表的 buckets Vec。我返回一个可变引用,因为我将改变返回的存储桶(例如,在向其中插入一个新条目(键值对)时)。

以上代码编译通过。

但是如果我摆脱中间变量 index 并计算 [] 括号内的索引,如下所示:

    fn pick_bucket(&mut self, key: K) -> &mut Bucket<K, V> {
let mut hasher = DefaultHasher::new();
key.hash(&mut hasher);
let hash = hasher.finish() as usize;
&mut self.buckets[hash % self.buckets.len()]
}

我会得到这个借用错误:

error[E0502]: cannot borrow `self.buckets` as immutable because it is also borrowed as mutable
--> src\lib.rs:30:34
|
26 | fn pick_bucket(&mut self, key: K) -> &mut Bucket<K, V> {
| - let's call the lifetime of this reference `'1`
...
30 | &mut self.buckets[hash % self.buckets.len()]
| -------------------------^^^^^^^^^^^^^^^^^^-
| | | |
| | | immutable borrow occurs here
| | mutable borrow occurs here
| returning this value requires that `self.buckets` is borrowed for `'1`

我认为上面的两个代码片段是等价的。它们有何不同,为什么第一个可以编译,为什么第二个不能?

编辑: 我认为第一个代码片段中 self.buckets 的不可变借用超出了范围,并在行尾处“无效” let index = ...;,所以当方法返回时,没有对 self.buckets 的共享引用;在第二个片段中,self.buckets 的不可变借用一直存在到方法返回(因此在那个时刻共享和可变引用共存)。如果这是正确的,为什么会这样?为什么 self.buckets 的不可变借用在第二种情况下到达 ] 括号时不会“失效”,而是在整个表达式(整个返回线)?

最佳答案

我相信您已经完全解决了您编辑中的问题。在第一个示例中,self.buckets 被不可变地借用,然后借用在语句末尾结束。在第二个示例中,self.buckets 被可变地借用,然后在同一语句中被不变地借用。这是不允许的。

self.buckets.len() 是临时的,它的生命周期规则(drop scope)在Temporary Scopes中解释。 :

Apart from lifetime extension, the temporary scope of an expression is the smallest scope that contains the expression and is one of the following:

  • The entire function body.
  • A statement.
  • The body of a if, while or loop expression.
  • The else block of an if expression.
  • The condition expression of an if or while expression, or a match guard.
  • The expression for a match arm.
  • The second operand of a lazy boolean expression.

这在注释中有更进一步的解释:

Temporaries that are created in the final expression of a function body are dropped after any named variables bound in the function body, as there is no smaller enclosing temporary scope.

所以 self.buckets.len() 借用一直持续到函数结束(在函数体之后,甚至在语句完成之后)。但更容易将其视为持续到语句末尾(在任何情况下都会如此)。

没有在单个语句内创建的“子表达式”放置范围。理论上这可能是可能的,但 Rust 并没有那么激进。

关于rust - 借用中间变量可绕过的错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70524766/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com