rust 我无法理解的自我相关的借用错误

jk9hmnmh  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(136)

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结构体:因此,生命周期参数。理想情况下,我希望在框架中同时使用map和list作为字段,但是如果框架有一个引用回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被借用了,而且似乎没有返回,但是编译器允许self.index_list = index_list:为什么?
我想做的事有解决办法吗?

3df52oht

3df52oht1#

这是我的想法,部分灵感来自Jmb的答案here
如前所述,我也非常希望HashMapFramework的一个字段。这似乎是不可能的,但据我所知,使用中间“保持器”结构似乎可以完成这项工作。

use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;
use std::fmt;

fn main() {
    let mut framework = Framework {
        index_list: Vec::new(),
        holder: Rc::new(RefCell::new(Holder{doc_map: HashMap::new()})),
    };
    framework.method_one();
}

#[derive(Debug, Clone)]
struct Framework<'a> {
    index_list: Vec<usize>,
    holder: Rc<RefCell<Holder<'a>>>,
}

#[derive(Debug, Clone)]
struct Holder<'a> {
    doc_map: HashMap<String, Doc<'a>>,
}

// necessary to implement this: otherwise you get stack overflow 
// on "{:#?}" because of all the self-referencing structures
impl fmt::Display for Holder<'_> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let mut s  = "hashmap keys:\n".to_string();
        for (key, value) in self.doc_map.clone().into_iter() {
            s.push_str(&format!("key {}\n", &key));
            
        };
        write!(f, "{}", s)
    }
}

#[derive(Debug, Clone)]
struct Doc<'a>{
    holder: Rc<RefCell<Holder<'a>>>,
}

impl Framework<'_> {
    fn method_one(&mut self){
        self.populate_map_and_list();
        println!("--- self.index_list {:?}\n", self.index_list);
        println!("--- self.holder {}\n", *self.holder.borrow());
        self.manipulate_more();
        println!("--- self.index_list {:?}\n", self.index_list);
        println!("--- self.holder {}\n", *self.holder.borrow());
    }
    
    fn populate_map_and_list(&mut self) {
        let rc_ptr = &self.holder;
        let doc:Doc = Doc {holder: (*rc_ptr).clone().into()} ;
        self.holder.borrow_mut().doc_map.insert("bubble".to_string(), doc);
        self.index_list.push(99);
    }
    
    fn manipulate_more(&mut self) {
        let rc_ptr = &self.holder;
        let doc:Doc = Doc {holder: (*rc_ptr).clone().into()} ;
        self.holder.borrow_mut().doc_map.insert("jubble".to_string(), doc);
        self.index_list.push(100);
    }
}

字符串
显然,这并不能使你从Doc到达Framework。所以Doc s需要引用的任何东西都必须保存在Holderstruct中。或者.
一个线程安全的版本也可以使用ArcMutex,这自然会带来一些与锁定相关的挑战。

相关问题