如何将 Rust ZipArchive 和 ZipFile 放入单个读取实现结构中,同时处理生命周期和借用规则
How to fit a Rust ZipArchive and ZipFile into a single Read-implementing struct, while dealing with lifetime and borrowing rules
这个问题可以用几种不同的方式提出,但我的最终目标是将一个文件从 ZipArchive
(Rust zip crate)封装到一个名为 ZipReader
的结构中,该结构实现了 Read,像这样:
struct ZipReader<R: Read + Seek> { ... }
impl<R: Read + Seek> ZipReader<R> {
fn from(src: R, filename: &str) -> ZipReader<R> { ... }
}
impl <R: Read + Seek> Read for ZipReader<R> { ... }
我这样做的努力包括从 src 流构建一个新的 ZipArchive
,然后使用 ZipArchive.by_name(name)
提取可以从中读取字节的 ZipFile<'a>
。
我 运行 遇到的问题是 ZipFile<'a>
结构引用了构造它的 &'a mut ZipArchive
的生命周期——这意味着 ZipArchive
必须保留在范围 和 在 ZipFile
.
的生命周期内保持可变借用
这种约束组合似乎无法将 zip 封装在新结构中:
pub struct ZipReader<R: Read + Seek> {
file: zip::read::ZipFile<'_>, // Have experimented with lifetimes here with no success
archive: ZipArchive<R>,
}
impl <R: Read + Seek> ZipReader<R> {
fn from(mut zip: R, name: &str) -> ZipReader<R> {
let archive = ZipArchive::new(zip);
let file = archive.by_name(name).unwrap();
ZipReader {
file: file,
archive: archive.unwrap(),
}
}
}
impl <R: Read + Seek> Read for ZipReader<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.file.read(buf)
}
}
我不能将 file
单独移动到返回的 ZipReader
中,因为 archive
会超出范围,但我不能将 archive
移动到 ZipReader
因为被file
.
借用
似乎修改 zip crate 并将 ZipFile
状态合并到 ZipArchive
中以消除生命周期问题是解决问题的一种方法。不修改别人的代码怎么能解决这个问题?
正如 Coder-256 提到的,owning_ref::OwningHandle
提供解决借用问题的功能,但不提供生命周期问题。有一个 open issue on the repo for owning_ref
描述了一个相同的情况并请求额外的功能来解决它,但它自 2017 年以来一直开放,没有解决方案。
我最终 modifying the zip crate 转移了基础流的所有权,而不是持有对 ZipArchive 的引用。这对我的目的来说已经足够令人满意了,但是像 owning_ref
这样的解决方案似乎是解决此类问题的正确方法。
这个问题可以用几种不同的方式提出,但我的最终目标是将一个文件从 ZipArchive
(Rust zip crate)封装到一个名为 ZipReader
的结构中,该结构实现了 Read,像这样:
struct ZipReader<R: Read + Seek> { ... }
impl<R: Read + Seek> ZipReader<R> {
fn from(src: R, filename: &str) -> ZipReader<R> { ... }
}
impl <R: Read + Seek> Read for ZipReader<R> { ... }
我这样做的努力包括从 src 流构建一个新的 ZipArchive
,然后使用 ZipArchive.by_name(name)
提取可以从中读取字节的 ZipFile<'a>
。
我 运行 遇到的问题是 ZipFile<'a>
结构引用了构造它的 &'a mut ZipArchive
的生命周期——这意味着 ZipArchive
必须保留在范围 和 在 ZipFile
.
这种约束组合似乎无法将 zip 封装在新结构中:
pub struct ZipReader<R: Read + Seek> {
file: zip::read::ZipFile<'_>, // Have experimented with lifetimes here with no success
archive: ZipArchive<R>,
}
impl <R: Read + Seek> ZipReader<R> {
fn from(mut zip: R, name: &str) -> ZipReader<R> {
let archive = ZipArchive::new(zip);
let file = archive.by_name(name).unwrap();
ZipReader {
file: file,
archive: archive.unwrap(),
}
}
}
impl <R: Read + Seek> Read for ZipReader<R> {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.file.read(buf)
}
}
我不能将 file
单独移动到返回的 ZipReader
中,因为 archive
会超出范围,但我不能将 archive
移动到 ZipReader
因为被file
.
似乎修改 zip crate 并将 ZipFile
状态合并到 ZipArchive
中以消除生命周期问题是解决问题的一种方法。不修改别人的代码怎么能解决这个问题?
正如 Coder-256 提到的,owning_ref::OwningHandle
提供解决借用问题的功能,但不提供生命周期问题。有一个 open issue on the repo for owning_ref
描述了一个相同的情况并请求额外的功能来解决它,但它自 2017 年以来一直开放,没有解决方案。
我最终 modifying the zip crate 转移了基础流的所有权,而不是持有对 ZipArchive 的引用。这对我的目的来说已经足够令人满意了,但是像 owning_ref
这样的解决方案似乎是解决此类问题的正确方法。