【发布时间】:2018-02-09 16:02:06
【问题描述】:
我有一个隐藏在 Mutex 后面的 Git 存储库:
pub struct GitRepo {
contents: Mutex<GitContents>,
workdir: PathBuf,
}
我想查询它,但最多只能查询一次:在它被查询之后,我只想使用我们第一次得到的结果。存储库具有git2::Repository 或结果向量。 Repository 是 Send 但不是 Sync。
enum GitContents {
Before { repo: git2::Repository },
After { statuses: Git },
}
struct Git {
statuses: Vec<(PathBuf, git2::Status)>,
}
GitContents 枚举反映了这样一个事实,即我们要么有要查询的存储库,要么有查询它的结果,但从来没有两者兼有。
我试图让 Rust 强制执行此属性,方法是让函数将存储库转换为状态消耗存储库生成状态向量:
fn repo_to_statuses(repo: git2::Repository, workdir: &Path) -> Git {
// Assume this does something useful...
Git { statuses: Vec::new() }
}
但是,我无法让 Mutex 很好地处理这个问题。到目前为止,我尝试编写一个函数,用谓词 P 查询 GitRepo,如果尚未查询,则替换 Mutex 中的值:
impl GitRepo {
fn search<P: Fn(&Git) -> bool>(&self, p: P) -> bool {
use std::mem::replace;
// Make this thread wait until the mutex becomes available.
// If it's locked, it's because another thread is running repo_to_statuses
let mut contents = self.contents.lock().unwrap();
match *contents {
// If the repository has been queried then just use the existing results
GitContents::After { ref statuses } => p(statuses),
// If it hasn't, then replace it with some results, then use them.
GitContents::Before { ref repo } => {
let statuses = repo_to_statuses(*repo, &self.workdir);
let result = p(&statuses);
replace(&mut *contents, GitContents::After { statuses });
result
},
}
}
}
虽然涉及到突变,但此方法只使用&self 而不是&mut self,因为无论是第一次还是第二次查询存储库,它都会返回相同的结果,即使还有更多工作要做首先。但 Rust 抱怨:
- 它拒绝将
repo移出我在repo_to_statuses(*repo, &self.workdir)中借用的内容,即使我知道该值应该在之后立即被替换。 (“不能移出借来的内容”) - 它也不喜欢我
replace-ing&mut *contents,因为我以match-ed 的值不变地借用内容。 (“不能将‘内容’借用为可变的,因为它也被借用为不可变的”)
有什么方法可以让借阅检查员相信我的意图?
【问题讨论】:
标签: rust borrow-checker