I'm implementing a simple Iterator for a struct that contains a ref:
extern crate zip;
extern crate quick_xml;
extern crate chrono;
use std::io::{Seek, Write, Read, Error};
use std::fs::File;
use xlsx_read::zip::read::ZipFile;
use xlsx_read::zip::result::ZipResult;
use xlsx_read::zip::ZipArchive;
use xlsx_read::zip::write::{FileOptions, ZipWriter};
use xlsx_read::quick_xml::Reader as XmlReader;
use xlsx_read::quick_xml::events::Event;
use std::io::BufReader;
use xlsx_read::chrono::prelude::*;
pub struct XlsxFile<'a> {
path: &'a str,
archive: ZipArchive<File>,
sheet_count: usize,
curr: usize,
}
impl<'a> XlsxFile<'a> {
pub fn from(path: &'a str) -> Result<XlsxFile, Error> {
let file = File::open(path)?;
let archive = ZipArchive::new(file)?;
let sheet_count = archive.len();
Ok(XlsxFile {
path: path,
archive: archive,
sheet_count,
curr: 0,
})
}
}
pub struct XlsxSheet<'a> {
pub name: &'a str,
pub index: usize,
}
impl<'a> Iterator for XlsxFile<'a> {
type Item = XlsxSheet<'a>;
fn next(&mut self) -> Option<XlsxSheet<'a>> {
loop {
if self.sheet_count > 0 &&
self.sheet_count > self.curr {
let zip_file = self.archive.by_index(self.curr).unwrap();
let file_name = zip_file.name();
if file_name.contains("xl/worksheets/sheet") {
let sheet = XlsxSheet {
name: file_name, // works fine if String::from(file_name) is used
index: self.curr,
};
self.curr += 1;
return Some(sheet);
}
self.curr += 1;
continue;
} else {
break;
}
}
return None;
}
}
static XLSX_FILE: &'static str = "<location_to_xlsx_file>";
fn main() {
let mut file = xlsx_read::XlsxFile::from(XLSX_FILE).unwrap();
file.for_each(|s| println!("idx: {:?}", s.name));
}
But I get the following error:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/xlsx_read.rs:50:45
|
50 | let zip_file = self.archive.by_index(self.curr).unwrap();
| ^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 46:5...
--> src/xlsx_read.rs:46:5
|
46 | / fn next(&mut self) -> Option<XlsxSheet<'a>> {
47 | | loop {
48 | | if self.sheet_count > 0 &&
49 | | self.sheet_count > self.curr {
... |
66 | | return None;
67 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/xlsx_read.rs:50:32
|
50 | let zip_file = self.archive.by_index(self.curr).unwrap();
| ^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 43:1...
--> src/xlsx_read.rs:43:1
|
43 | impl<'a> Iterator for XlsxFile<'a> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...so that the expression is assignable:
expected std::option::Option<xlsx_read::XlsxSheet<'a>>
found std::option::Option<xlsx_read::XlsxSheet<'_>>
error: aborting due to previous error
For more information about this error, try `rustc --explain E0495`.
My question is, how to tell Rust compiler to use appropriate lifetime here? Even though I've defined XlsxSheet<'a> with lifetime modifier and want to tie name to &'a str but somehow this doesn't translate into a valid Rust code.
Easy Solution : This problem can be trivially fixed by using String
instead of &'a str
.
Explanation :
I don't know the definition of by_index
, which seems to be quite crucial to this problem. The following reasoning is pure guess and it's not reliable. It's offered only for reference.
self.archive
borrows self
(which is valid over the entire scope, let's say the lifetime is named 'me
), and has lifetime 'me
. by_index
has lifetime 'me
.XlsxSheet<'me>
is not compatible with XlsxSheet<'a>
(which is expected)! What we want here is XlsxSheet<'me>
being a subtype of XlsxSheet<'a>
, which in turn implies 'me
being a subtype of 'a
, if XlsxSheet
is covariant. Therefore, you can state them explicitly
fn next(&mut self) -> Option<XlsxSheet<'a>> where Self: 'a
// or
impl<'a> Iterator for XlsxFile<'a> + 'a
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.