【问题标题】:Extracting an archive with progress bar - mutable borrow error使用进度条提取档案 - 可变借用错误
【发布时间】:2018-10-26 07:25:47
【问题描述】:

我正在尝试提取 .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函数来获取当前位置。

有没有办法解决这个问题,要么强制编译器忽略可变借用,要么以某种不可变的方式获取位置?

【问题讨论】:

  • seek() 采用&amp;mut self,所以这是可变借用发生的地方。查看 crate 文档,您不能使用 decoder.total_in() 代替吗?
  • 请查看如何创建minimal reproducible example,然后查看edit 您的问题以包含它。我们无法分辨代码中存在哪些 crate、类型、特征、字段等。具体而言,我们无法分辨 BzDecoderArchive 来自哪里,以及其他一些特征。尝试在Rust Playground 上重现您的错误,或者您可以在全新的 Cargo 项目中重现它。还有Rust-specific MCVE tips

标签: file rust borrowing


【解决方案1】:

文件有点特殊。通常的read()seek()write() 方法(在ReadSeekWrite 特征上定义)通过可变引用获取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>

但是,所有提到的特征也针对&amp;File 实现,即对于文件的不可变引用:

因此,即使您只有对该文件的只读引用,您也可以修改该文件。对于这些实现,Self 类型是&amp;File,因此通过可变引用接受self 实际上意味着接受&amp;mut &amp;File,即对文件引用的可变引用。

您的代码将&amp;f 传递给BzDecoder::new(),创建了一个不可变的借用。稍后您调用f.seek(SeekFrom::Current(0)),它通过可变引用将f 传递给seek。但是,这是不允许的,因为您已经有了文件的不可变借用。解决方案是在&amp;File 上使用Seek 实现:

(&mut &f).seek(SeekFrom::Current(0))

或者稍微简单一点

(&f).seek(SeekFrom::Current(0))

这只会创建第二个不可变借用,这是 Rust 的引用规则所允许的。

我创建了一个playground example demonstrating that this works。如果您将(&amp;f) 替换为f,则会得到最初遇到的错误。

【讨论】:

  • 非常感谢。我不知道 &File 特征的实现。但是(&amp;f).seek() 版本是如何工作的呢?指针不应该根据 trait 是可变的吗?
  • @thanasis2028 (&amp;f).seek() 的工作原理与f.seek() 的工作原理完全相同。首先查找接收器本身的类型,例如T,然后查找&amp;T,然后查找&amp;mut T,然后查找通过迭代取消引用接收器获得的对象。有关详细信息,请参阅this answer
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-12
  • 2021-06-04
  • 1970-01-01
  • 2018-04-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多