Reputation: 404
I found code for a function that returns an iterator over the lines of a text file:
pub fn read_file_iterator(path: &str) -> io::Result<Lines<BufReader<File>>> {
let file = File::open(path)?;
let buf_reader = BufReader::new(file);
// lines() returns an iterator over lines
Ok(buf_reader.lines())
}
Having zero experience with Rust, I thought I could adopt this code for a file which is a part of a ZIP archive:
use std::io::prelude::*;
use std::io::{self, BufReader, Lines, Cursor};
use std::path::Path;
use zip::read::ZipFile;
pub fn read_zip_file(_filename: &Path) -> io::Result<Lines<BufReader<ZipFile>>> {
let reader = Cursor::new(std::fs::read(_filename)?);
let mut zip_archive = zip::ZipArchive::new(reader)?;
assert_eq!(1, zip_archive.len());
let zip_file: ZipFile = zip_archive.by_index(0).unwrap(); // E: `zip_archive` is borrowed here"
let buf_reader = BufReader::new(zip_file);
Ok(buf_reader.lines()) // E: returns a value referencing data owned by the current function
}
Building this code results in an error (see also the comments that reflect the error details):
cannot return value referencing local variable
zip_archive
What is the right way of writing such a function?
Upvotes: 2
Views: 556
Reputation: 2516
The issue is that read_zip_file
is doing much more than the read_file_iterator
- ZipFile
mutably borrows zip_archive
which then goes out of scope. ZipFile
does not exist without ZipArchive
. This is not allowed, as the borrow checker suggested.
One approach would be to unzip this particular file as a temporary (as your ordinary zip browser does) and then do the iteration as in your first snippet. If the file is small and you know it beforehand - you better just collect the data, with e.g. read_to_end which ZipFile
implements.
Upvotes: 1