返回拥有的物料和对物料的引用



我正在使用git2机箱,希望为repo获取Statuses,并将其存储在我的应用程序结构中,以便以后重用,因为创建成本很高。问题是Statuses引用了创建它的Repository。就我从这个问题中所理解的:为什么可以';我是否将一个值和对该值的引用存储在同一结构中?,我不能返回一个拥有的项以及对它的引用,因为当它从函数返回并移动时,拥有的项的地址会更改,从而使引用无效。以下是我试图做的一个最简单的例子,解决这个问题的正确方法是什么?

use git2::{Repository, Statuses};
struct App<'a> {
repo: Repository,
statuses: Statuses<'a>,
}
impl<'a> App<'a> {
fn new() -> Self {
let repo = Repository::open("myrepo").unwrap();
let statuses = repo.statuses(None).unwrap();
App { repo, statuses }
}
}
fn main() {
let mydata = App::new();
dbg!(mydata.statuses.len());
}

以下是我找到的唯一解决方案(也是从上面的问题中得出的(,即使Statuses可选,并在Repository已经从::new()返回后更改应用程序数据。这看起来很粗糙,也不地道,而且无论如何都不会编译。

use git2::{Repository, Statuses};
struct App<'a> {
repo: Repository,
statuses: Option<Statuses<'a>>,
}
impl<'a> App<'a> {
fn new() -> Self {
let repo = Repository::open("myrepo").unwrap();
App {
repo,
statuses: None,
}
}
}
fn main() {
let mut mydata = App::new();
mydata.statuses = mydata.repo.statuses(None).ok();
dbg!(mydata.statuses.unwrap().len());
}
error[E0597]: `mydata.repo` does not live long enough
--> src/main.rs:19:23
|
19 |     mydata.statuses = mydata.repo.statuses(None).ok();
|                       ^^^^^^^^^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
20 |     dbg!(mydata.statuses.unwrap().len());
21 | }
| -
| |
| `mydata.repo` dropped here while still borrowed
| borrow might be used here, when `mydata` is dropped and runs the destructor for type `App<'_>`

编辑:一些附加上下文:我正在用egui制作一个应用程序,所以应用程序结构就是应用程序状态。除此之外,它还会在一个目录中列出所有git转发,并显示它们的状态信息。我测量了repo.statuses(None).unwrap()调用,对于大约10个存储库,总共花费了4ms,所以调用应用程序的每个循环太慢了。我能想到的显而易见的解决方案是将数据存储在应用程序的状态(应用程序(中,但这似乎不可能,所以我正在寻找其他方法。

我认为有两种解决方案:

  • Statuses对象中复制所需的数据,然后释放它
  • 使用像self_cell这样的外部机箱来创建一个自引用对象。注意,该对象然后不能再提供对Repositorymut访问

我认为,在您的情况下,第一个选项是可行的,因为据我所知,Statuses只是一个路径集合,每个路径都有一个状态。

use std::collections::HashMap;
use git2::{Repository, Status};
struct App {
repo: Repository,
statuses: HashMap<String, Status>,
}
impl App {
fn new() -> Self {
let repo = Repository::open(".").unwrap();
let statuses = repo
.statuses(None)
.unwrap()
.iter()
.map(|el| (el.path().unwrap().to_string(), el.status()))
.collect::<HashMap<_, _>>();
App { repo, statuses }
}
}
fn main() {
let mydata = App::new();
dbg!(mydata.statuses.len());
println!("{:#?}", mydata.statuses);
}
[src/main.rs:24] mydata.statuses.len() = 2
{
"Cargo.toml": WT_MODIFIED,
"src/main.rs": INDEX_MODIFIED | WT_MODIFIED,
}

最新更新