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

问题描述 投票:0回答:1

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
:怎么来的?

我正在尝试做的事情有解决方案吗?

rust borrow-checker
1个回答
0
投票

受到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 的克隆对我来说确实看起来很奇怪......但它似乎可以完成工作。

    

© www.soinside.com 2019 - 2024. All rights reserved.