Rust 将对象作为可变对象借用两次,用于不相关的连续使用

Rust 将对象作为可变对象借用两次,用于不相关的连续使用,rust,borrow-checker,Rust,Borrow Checker,我正在尝试实现一个抽象,它允许我从目录或zip文件中读取数据。我从实现这类东西开始: pub trait FileOpener结果; } 发布结构DirectoryFileOpener{ pub fn new(根:&'a Path)->Self{ DirectoryFileOpener{root} } } DirectoryFileOpener结果的impl{ 确定(文件::打开(self.root.join(文件名))?) } } 但后来我意识到zip rs包的zip::ZipFile是从它

我正在尝试实现一个抽象,它允许我从目录或zip文件中读取数据。我从实现这类东西开始:

pub trait FileOpener结果;
}
发布结构DirectoryFileOpener{
pub fn new(根:&'a Path)->Self{
DirectoryFileOpener{root}
}
}
DirectoryFileOpener结果的impl{
确定(文件::打开(self.root.join(文件名))?)
}
}
但后来我意识到zip rs包的zip::ZipFile是从它所在的zip::ZipArchive的可变引用构建的,因此我最终得到以下代码:

使用std::path::path;
使用std::error::error;
使用std::fs::File;
使用std::io::prelude::*;
使用zip::{ZipArchive,read::ZipFile};
使用std::marker::PhantomData;
文件开启器结果;
}
发布结构DirectoryFileOpener{
pub fn new(根:&'a Path)->Self{
DirectoryFileOpener{root}
}
}
DirectoryFileOpener结果的impl{
确定(文件::打开(self.root.join(文件名))?)
}
}
pub结构ZipFileOpener
}
恳求{
新酒吧(邮编:ZipArchive)->Self{
ZipFileOpener{zip,幻影:幻影数据}
}
}
ZipFileOpener的impl;
fn打开(&'a mut self,文件名:&str)->结果{
让file=file::open(root)?;
让mut-zip=ZipArchive::新建(文件)?;
让a=Self::解析a(zip.by_name(“a.txt”)?;
让b=Self::parse_b(zip.by_name(“b.txt”)?,a)?;
}

这让我完全不舒服,因为函数by_name()也借用了zip作为可变的,并且还被调用了两次!为什么在这里可以借用zip作为可变项两次,但在前面的例子中不允许?

在深入研究问题和Rust的语义,并在trentcl的注释基础上,我开始意识到,问题本质上归结为定义FileOpener特性,其中生存期参数绑定到关联的类型,而不是特性本身,例如

pub trait FileOpener {
    type ReaderType: Read;

    fn open(&'a mut self, file_name: &str) -> Result<Self::ReaderType, Box<dyn Error>>;
}


impl<'a, R: Read + Seek> FileOpener for ZipFileOpener<R> {
    type ReaderType = ZipFile<'a>;
    ...
}
pub-trait文件开启器{
类型读取器类型:读取;
fn打开(&'a mut self,文件名:&str)->结果;
}
impl;
...
}
然而,这是众所周知的,并没有支持生锈。然而,GAT RFC确实提到,在某些情况下,可以通过将生存期绑定到特征本身并在接收函数中使用更高秩特征边界(HRTB)来避免该问题,从而产生该问题的以下工作解决方案:

pub trait FileOpener<'a> {
    type ReaderType: Read;

    fn open(&'a self, file_name: &str) -> Result<Self::ReaderType, Box<dyn Error>>;
}

...

fn load<T: for<'a> FileOpener<'a>>(opener: T) -> ... {
    let a = parse_a(opener.open("a.txt")?)?;
    let b = parse_b(opener.open("b.txt")?, a)?;
}
pub trait FileOpener结果;
}
...
fn加载>(开启器:T)->。。。{
设a=parse_a(opener.open(“a.txt”)?)?;
设b=parse_b(opener.open(“b.txt”)?,a)?;
}

这是因为HRTB允许我们将T绑定到FileOpener,而无需将特定的生存期绑定到它,这就为每次调用opener.open()启用了不同生存期的后期绑定。

您不显示
parse\u a
parse\u b
的声明。这些可能也很重要。我没有包括它们,因为它们很长,但它们基本上可以替换为使用读取器并基于文件数据返回一些输出的内容(例如,返回第5个字节)。此外,这些函数的任何可能实现如何使第二个用例编译而第一个用例失败?他们实际上接收到相同的参数(一个实现读取特性的对象),这是否回答了您的问题?tl;dr the duplicate:
&'a self
通常是一个错误<代码>&“多个自我”实际上总是一个错误。只需删除那些
'a
s;我明白了,他们过度训练了生命。我明白你的意思,把它们去掉是有道理的。但是,这意味着我不能声明,例如,
type ReaderType=ZipFile