Извлечение архива с индикатором выполнения - изменяемая ошибка заимствования - PullRequest
0 голосов
/ 26 октября 2018

Я пытаюсь извлечь файл .tar.bz (или .tar.wh независимо от того, что на самом деле), а также иметь возможность получить отчет о прогрессе хх%.Пока у меня есть это:

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 как изменяемый;Я использую только функцию поиска, чтобы получить текущую позицию.

Есть ли способ обойти это, либо заставляя компилятор игнорировать изменяемый заем, либо получая позицию каким-то неизменным образом?

1 Ответ

0 голосов
/ 26 октября 2018

Файлы немного особенные.Обычные методы 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 по изменяемой ссылке.Однако это не разрешено, поскольку у вас уже есть неизменный заем файла.Решение состоит в том, чтобы использовать Seek реализацию вместо &File:

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

или немного проще

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

Это только создает второй неизменный заем, который разрешен Rust'sправила для ссылок.

Я создал пример игровой площадки, демонстрирующий, что это работает .Если вы замените (&f) на f, вы получите ошибку, которую вы изначально получили.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...