我有一个Git仓库,它被隐藏在一个Mutex
后面:
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)>,
}
< p > GitContents
枚举反映了我们要么有可查询的存储库,要么有查询其结果,但两者不可能同时存在。
我试图通过使将存储库转换为状态的函数在产生状态向量时“消耗”存储库来强制执行此属性:
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)
中借用的内容,即使我知道该值应立即被替换。(“cannot move out of borrowed content”) - 它也不喜欢我对
&mut *contents
进行replace
,因为我将内容以不可变的方式借用作为match
的值。(“cannot borrow 'contents' as mutable because it is also borrowed as immutable”)
有没有办法说服borrow checker我的意图?