使用进度条提取存档 - 可变借用错误
Extracting an archive with progress bar - mutable borrow error
我正在尝试提取一个 .tar.bz 文件(实际上是 .tar.whatever)并且还能够获得 xx% 的进度报告。到目前为止我有这个:
pub fn extract_file_with_progress<P: AsRef<Path>>(&self, path: P) -> Result<()> {
let path = path.as_ref();
let size = fs::metadata(path)?;
let mut f = File::open(path)?;
let decoder = BzDecoder::new(&f);
let mut archive = Archive::new(decoder);
for entry in archive.entries()? {
entry?.unpack_in(".")?;
let pos = f.seek(SeekFrom::Current(0))?;
}
Ok(())
}
我的想法是使用 pos/size
来获取百分比,但是编译上面的函数让我得到错误 cannot borrow f as mutable because it is also borrowed as immutable
。
我明白错误的含义,但我并没有真正使用 f
作为可变的;我只使用seek函数获取当前位置
有没有办法解决这个问题,要么强制编译器忽略可变借用,要么以某种不可变方式获取位置?
文件有点特殊。通常的 read()
和 seek()
和 write()
方法(在 Read
、Seek
和 Write
特征上定义)采用 self
可变参考:
fn read(&mut self, buf: &mut [u8]) -> Result<usize>
fn seek(&mut self, pos: SeekFrom) -> Result<u64>
fn write(&mut self, buf: &[u8]) -> Result<usize>
然而,所有提到的特征也为 &File
实现,即 不可变 对文件的引用:
因此,即使您只有对文件的只读引用,也可以修改该文件。对于这些实现,Self
类型是 &File
,因此通过可变引用接受 self
实际上意味着接受 &mut &File
,一个对文件引用的可变引用。
您的代码将 &f
传递给 BzDecoder::new()
,创建不可变借用。稍后您调用 f.seek(SeekFrom::Current(0))
,它通过可变引用将 f
传递给 seek
。但是,这是不允许的,因为您已经有了不可变的文件借用。解决方案是在 &File
上使用 Seek
实现:
(&mut &f).seek(SeekFrom::Current(0))
或者稍微简单一些
(&f).seek(SeekFrom::Current(0))
这只会创建第二个不可变借用,这是 Rust 的引用规则所允许的。
我创建了一个 playground example demonstrating that this works。如果您将 (&f)
替换为 f
,您会得到最初得到的错误。
我正在尝试提取一个 .tar.bz 文件(实际上是 .tar.whatever)并且还能够获得 xx% 的进度报告。到目前为止我有这个:
pub fn extract_file_with_progress<P: AsRef<Path>>(&self, path: P) -> Result<()> {
let path = path.as_ref();
let size = fs::metadata(path)?;
let mut f = File::open(path)?;
let decoder = BzDecoder::new(&f);
let mut archive = Archive::new(decoder);
for entry in archive.entries()? {
entry?.unpack_in(".")?;
let pos = f.seek(SeekFrom::Current(0))?;
}
Ok(())
}
我的想法是使用 pos/size
来获取百分比,但是编译上面的函数让我得到错误 cannot borrow f as mutable because it is also borrowed as immutable
。
我明白错误的含义,但我并没有真正使用 f
作为可变的;我只使用seek函数获取当前位置
有没有办法解决这个问题,要么强制编译器忽略可变借用,要么以某种不可变方式获取位置?
文件有点特殊。通常的 read()
和 seek()
和 write()
方法(在 Read
、Seek
和 Write
特征上定义)采用 self
可变参考:
fn read(&mut self, buf: &mut [u8]) -> Result<usize>
fn seek(&mut self, pos: SeekFrom) -> Result<u64>
fn write(&mut self, buf: &[u8]) -> Result<usize>
然而,所有提到的特征也为 &File
实现,即 不可变 对文件的引用:
因此,即使您只有对文件的只读引用,也可以修改该文件。对于这些实现,Self
类型是 &File
,因此通过可变引用接受 self
实际上意味着接受 &mut &File
,一个对文件引用的可变引用。
您的代码将 &f
传递给 BzDecoder::new()
,创建不可变借用。稍后您调用 f.seek(SeekFrom::Current(0))
,它通过可变引用将 f
传递给 seek
。但是,这是不允许的,因为您已经有了不可变的文件借用。解决方案是在 &File
上使用 Seek
实现:
(&mut &f).seek(SeekFrom::Current(0))
或者稍微简单一些
(&f).seek(SeekFrom::Current(0))
这只会创建第二个不可变借用,这是 Rust 的引用规则所允许的。
我创建了一个 playground example demonstrating that this works。如果您将 (&f)
替换为 f
,您会得到最初得到的错误。