MRE:
use std::collections::HashMap;
fn main() {
let mut framework = Framework {
index_list: Vec::new(),
};
framework.method_one();
}
#[derive(Debug)]
struct Framework {
index_list: Vec<usize>,
}
#[derive(Debug)]
struct Doc<'a> {
framework: &'a Framework,
}
impl Framework {
fn method_one(&mut self){
println!("method one");
let index_list: Vec<usize>;
let (doc_map, index_list) = self.get_map_and_list();
println!("map {:#?}, list {:#?}", doc_map, self.index_list);
self.index_list = index_list;
// uncommenting this causes the issue:
// self.manipulate_list_more(doc_map);
}
fn get_map_and_list(&self) -> (HashMap<String, Doc>, Vec<usize>) {
let mut doc_map = HashMap::new();
doc_map.insert("bubble".to_string(), Doc{framework: &self});
let mut index_list: Vec<usize> = Vec::new();
index_list.push(99);
(doc_map, index_list)
}
fn manipulate_list_more(&mut self, doc_map: HashMap<String, Doc>) {
// NB whether this is "&self" or "&mut self" is irrelevant ...
println!("submethod_two");
// even if this is commented out we still get the error...
// showing that the commands in this method are irrelevant to the problem involved
// self.index_list.push(100);
}
}
当然,这是我正在做的事情的简化版本。
Doc
结构必须具有对 Framework
结构的引用:因此有生命周期参数。理想情况下,我希望将地图和列表都作为框架中的字段,但是如果框架有一个引用回 Doc
的字段(就像在 HashMap<String, Doc>
中那样)(也Framework
是一个 pyclass
,它不允许生命周期!)。
现在我在操作框架的
Vec<usize>
字段时遇到了问题。如果取消注释self.manipulate_list_more(...)
,您将看到错误:
error[E0506]: cannot assign to `self.index_list` because it is borrowed
--> src\main.rs:28:3
|
26 | let (doc_map, index_list) = self.get_map_and_list();
| ----------------------- `self.index_list` is borrowed here
27 | println!("map {:#?}, list {:#?}", doc_map, self.index_list);
28 | self.index_list = index_list;
| ^^^^^^^^^^^^^^^ `self.index_list` is assigned to here but it was already borrowed
29 | self.manipulate_list_more(doc_map);
| ------- borrow later used here
...我不明白的是为什么借用不会开始...然后结束。从
self.get_map_and_list()
归还之后,不是已经借了self
然后又还了吗?貌似不是。但这样做会有什么问题呢?
其次,问题行被注释掉了,为什么这个问题不会出现呢?
self
被借用了,貌似没有归还,但是编译器却允许self.index_list = index_list
:怎么来的?
我正在尝试做的事情有解决方案吗?
受到Jmb(解释了这个难题)的这个答案的启发,我想出了这个奇怪的东西:
use std::collections::HashMap;
use std::rc::{Rc, Weak};
fn main() {
let mut framework = Framework {
index_list: Vec::new(),
};
let framework = framework.initial_method();
framework.more_stuff();
}
#[derive(Debug, Clone)]
struct Framework {
index_list: Vec<usize>,
}
#[derive(Debug)]
struct Doc {
framework: Weak<Framework>,
}
impl Framework {
fn initial_method(mut self) -> Self { // self moved here
println!("method one");
let index_list: Vec<usize>;
let mut cloned_self = self.clone();
// self moved again:
let (doc_map, index_list) = self.get_map_and_list();
println!("map {:#?}, list {:#?}", doc_map, index_list);
cloned_self.index_list = index_list;
let _ = &cloned_self.manipulate_list_more(&doc_map);
println!("map {:#?}, list {:#?}", doc_map, cloned_self.index_list);
// return self for on-going use
cloned_self
}
fn get_map_and_list(mut self) -> (HashMap<String, Doc>, Vec<usize>) { // move self
let mut doc_map = HashMap::new();
let rc = Rc::new(self);
doc_map.insert("bubble".to_string(), Doc{framework: Rc::downgrade(&rc)});
let mut index_list: Vec<usize> = Vec::new();
index_list.push(99);
(doc_map, index_list)
}
fn manipulate_list_more(&mut self, doc_map: &HashMap<String, Doc>) {
println!("submethod_two");
self.index_list.push(100);
}
fn more_stuff(&self) {
println!("back to more conventional method...")
}
}
...他/她的回答也给了我一个关于如何实现我最初想要的东西的公平线索,即将
HashMap
作为 Framework
的字段。我已经阅读了有关 RefCell
和 Rc
的章节,但完全没有理解(Arc
是不同的,因为使用它可以快速让你启动并运行并行处理,所以我必须掌握它...... ).
对我来说,我有一个问题和一个观察:观察结果是,在非常常见的情况下,您希望
struct
引用其他 struct
,使用生命周期,正如默认建议的那样当然,编译器肯定会让你的生活变得非常复杂,并且在大多数情况下确实没有必要:如果未设置 Weak
,你的 Rc<Option>
会给你一个 None
,你必须允许它。我建议对于大多数此类情况来说这会更惯用。
我开始问自己的问题是:Rust 解决方案什么时候变得“人为”或“不自然”?例如,这个 self
的克隆对我来说确实看起来很奇怪......但它似乎可以完成工作。