我正在和Rust一起工作,我正在与某种情况作斗争,以克服编译器借用检查器。
我有一个需要实现Struct的情况。在实现的初始化过程中,我需要在它完全初始化之前将对Struct的引用Repo
传递给另一个实现。
第二个结构Backend
实现与数据库的连接。连接完成后,需要从数据库中提取信息,并填充第一个结构的字段。在此过程中,需要使用数据库中的信息更新Backend
结构
这是一个MUC。
use std::{collections::HashMap, borrow::BorrowMut};
use serde_json::Value;
#[derive(Debug)]
pub enum BackendError {
Generic(String),
}
impl From<sqlite::Error> for BackendError{
fn from(error: sqlite::Error) -> Self{
BackendError::Generic(error.to_string())
}
}
pub struct Entry {
pub version: String,
pub val: Value,
}
// Information needed by the repository functionality
pub struct Repo{
pub values: HashMap<String,HashMap<String, Entry>>,
backend: Box<dyn Backend>
}
impl Repo {
pub fn new() -> Repo{
// initialize Persistence backend and load any prior status_values based on backend selection
let inst = init_backend_provider();
let repo = Repo {
values: HashMap::new(),
backend: inst ,
};
match repo.backend.load(&repo){
Ok(s) => s,
Err(e) => log::error!("{:?}", e),
}
repo
}
}
// ---------------------------------------------------
pub trait Backend: Send + Sync{
fn load(&self, repo: &Repo) -> Result<(), BackendError>;
}
pub fn init_backend_provider() -> Box<dyn Backend>{
Box::new(DB::new())
}
pub struct DB{}
impl DB{
fn new () -> Self{
DB{}
}
}
impl Backend for DB{
fn load(&self, repo: &Repo) -> Result<(), BackendError>{
// let key_value = repo.values.entry("key".to_string()).or_insert(HashMap::new());
Ok(())
}
}
fn main(){
let repo = Repo::new();
}
我得到的错误是显而易见的。如果它是一个引用,我就不能借用可变的数据。
我试图将其作为一个可变引用& mut.... match repo. backend. load(& mut repo)...这会导致编译器抱怨我试图从一个已经是不可变的借位中作为可变借位。
let mut repo = Repo {
values: HashMap::new(),
backend: inst ,
};
match repo.backend.load(&mut repo)
说来话长,我尝试了多种组合来使repo
可变,但没有成功。
我想做的是
当我调用load()
时,我希望传递Struct引用。这样我就可以查看哈希MapValue
。我希望查看第一级条目,或者创建一个新条目,或者拉取该条目并更新它。在这种情况下,它总是需要作为初始化过程的一部分来创建。一旦我创建了该条目,我将调用DB并请求一个特定表的所有可用字段。这些都可以工作,所以我不会用可以工作的代码重载MUC。
1条答案
按热度按时间gajydyqb1#
我认为你应该问自己的问题不是“我如何使它可变?”而是“我应该如何真正设计我的结构体和接口?"。
你现在的API意味着初始化一个
Backend
需要......它本身?这完全是无稽之谈。为什么这么说呢?因为
Backend::load
需要一个&Repo
,它包含一个Backend
,所以load
把它自己作为一个参数。rust 借检查员抱怨这一点是正确的;你对它抱怨的解释是错误的。2你的问题不是易变性,而是你的API没有意义。
你实际上应该做的是:不要给予
Backend::init
一个自身的引用。它只需要values
,所以给它一个引用。然后它就工作了:当然还有很多其他的架构方法来解决这个自引用API,基本的问题是如果
Repo
需要一个Backend
,但是Backend
也需要一个Repo
,那么你的依赖树就不是一棵树,而是一个圆,你应该问自己:谁真正依赖于什么?然后构建一个结构布局,其依赖关系实际上是一棵树。