如何修复 Rust 中的“.. 在循环的前一次迭代中在这里被可变地借用”?
How to fix ".. was mutably borrowed here in the previous iteration of the loop" in Rust?
我必须迭代键,通过键在 HashMap 中找到值,可能在找到的结构中做一些繁重的计算作为值(惰性 => 改变结构)并将它缓存 return 在 Rust 中.
我收到以下错误消息:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:25:26
|
23 | fn it(&mut self) -> Option<&Box<Calculation>> {
| - let's call the lifetime of this reference `'1`
24 | for key in vec!["1","2","3"] {
25 | let result = self.find(&key.to_owned());
| ^^^^ `*self` was mutably borrowed here in the previous iteration of the loop
...
28 | return result
| ------ returning this value requires that `*self` is borrowed for `'1`
这里是 code in playground.
use std::collections::HashMap;
struct Calculation {
value: Option<i32>
}
struct Struct {
items: HashMap<String, Box<Calculation>> // cache
}
impl Struct {
fn find(&mut self, key: &String) -> Option<&Box<Calculation>> {
None // find, create, and/or calculate items
}
fn it(&mut self) -> Option<&Box<Calculation>> {
for key in vec!["1","2","3"] {
let result = self.find(&key.to_owned());
if result.is_some() {
return result
}
}
None
}
}
- 我无法避免循环,因为我必须检查多个键
- 我必须使其可变(
self
和结构),因为可能的计算会改变它
关于如何更改设计(因为 Rust 强制以一种有意义的不同方式思考)或解决它的任何建议?
PS。代码还有一些其他问题,但让我们拆分问题并先解决这个问题。
可能不是最简洁的方法,但它可以编译。这个想法是不存储在临时结果中找到的值,以避免别名:如果存储结果,self
将被借用。
impl Struct {
fn find(&mut self, key: &String) -> Option<&Box<Calculation>> {
None
}
fn it(&mut self) -> Option<&Box<Calculation>> {
for key in vec!["1","2","3"] {
if self.find(&key.to_owned()).is_some() {
return self.find(&key.to_owned());
}
}
None
}
}
您不能使用 独占 访问权限进行缓存。您不能将 Rust 引用视为通用指针(顺便说一句:&String
和 &Box<T>
是双重间接寻址,并且在 Rust 中非常单一。临时使用 &str
或 &T
借用)。
&mut self
不仅意味着可变,而且 独占 和可变,所以你的缓存支持只返回一个项目,因为它的引用 returns 必须只要它存在,就保持 self
“锁定”状态。
你需要让借阅检查员相信 find
returns 的东西不会在你下次调用它时突然消失。目前没有这样的保证,因为接口不会阻止你调用,例如items.clear()
(借用检查器检查函数的接口允许什么,而不是函数实际做什么)。
您可以通过使用 Rc
或使用实现 a memory pool/arena.
的板条箱来做到这一点
struct Struct {
items: HashMap<String, Rc<Calculation>>,
}
fn find(&mut self, key: &str) -> Rc<Calculation>
这样,如果您克隆 Rc
,它将在需要时一直存在,独立于缓存。
您还可以通过内部可变性使其变得更好。
struct Struct {
items: RefCell<HashMap<…
}
这将允许您的记忆 find
方法使用共享借用而不是独占借用:
fn find(&self, key: &str) -> …
对于方法的调用者来说,这更容易使用。
我必须迭代键,通过键在 HashMap 中找到值,可能在找到的结构中做一些繁重的计算作为值(惰性 => 改变结构)并将它缓存 return 在 Rust 中.
我收到以下错误消息:
error[E0499]: cannot borrow `*self` as mutable more than once at a time
--> src/main.rs:25:26
|
23 | fn it(&mut self) -> Option<&Box<Calculation>> {
| - let's call the lifetime of this reference `'1`
24 | for key in vec!["1","2","3"] {
25 | let result = self.find(&key.to_owned());
| ^^^^ `*self` was mutably borrowed here in the previous iteration of the loop
...
28 | return result
| ------ returning this value requires that `*self` is borrowed for `'1`
这里是 code in playground.
use std::collections::HashMap;
struct Calculation {
value: Option<i32>
}
struct Struct {
items: HashMap<String, Box<Calculation>> // cache
}
impl Struct {
fn find(&mut self, key: &String) -> Option<&Box<Calculation>> {
None // find, create, and/or calculate items
}
fn it(&mut self) -> Option<&Box<Calculation>> {
for key in vec!["1","2","3"] {
let result = self.find(&key.to_owned());
if result.is_some() {
return result
}
}
None
}
}
- 我无法避免循环,因为我必须检查多个键
- 我必须使其可变(
self
和结构),因为可能的计算会改变它
关于如何更改设计(因为 Rust 强制以一种有意义的不同方式思考)或解决它的任何建议?
PS。代码还有一些其他问题,但让我们拆分问题并先解决这个问题。
可能不是最简洁的方法,但它可以编译。这个想法是不存储在临时结果中找到的值,以避免别名:如果存储结果,self
将被借用。
impl Struct {
fn find(&mut self, key: &String) -> Option<&Box<Calculation>> {
None
}
fn it(&mut self) -> Option<&Box<Calculation>> {
for key in vec!["1","2","3"] {
if self.find(&key.to_owned()).is_some() {
return self.find(&key.to_owned());
}
}
None
}
}
您不能使用 独占 访问权限进行缓存。您不能将 Rust 引用视为通用指针(顺便说一句:&String
和 &Box<T>
是双重间接寻址,并且在 Rust 中非常单一。临时使用 &str
或 &T
借用)。
&mut self
不仅意味着可变,而且 独占 和可变,所以你的缓存支持只返回一个项目,因为它的引用 returns 必须只要它存在,就保持 self
“锁定”状态。
你需要让借阅检查员相信 find
returns 的东西不会在你下次调用它时突然消失。目前没有这样的保证,因为接口不会阻止你调用,例如items.clear()
(借用检查器检查函数的接口允许什么,而不是函数实际做什么)。
您可以通过使用 Rc
或使用实现 a memory pool/arena.
struct Struct {
items: HashMap<String, Rc<Calculation>>,
}
fn find(&mut self, key: &str) -> Rc<Calculation>
这样,如果您克隆 Rc
,它将在需要时一直存在,独立于缓存。
您还可以通过内部可变性使其变得更好。
struct Struct {
items: RefCell<HashMap<…
}
这将允许您的记忆 find
方法使用共享借用而不是独占借用:
fn find(&self, key: &str) -> …
对于方法的调用者来说,这更容易使用。