I am writing a program in Rust that reads data from excel sheet and populates objects using that data. To convert each row of excel sheet into a Test
object, I implemted From<std::slice::Iter<'_, calamine::DataType>>
for Test
.
My code looks like below.
use calamine::{open_workbook, DataType, Reader, Xlsx};
use std::convert::From;
use std::path::Path;
use std::slice::Iter;
#[derive(Debug)]
pub struct Test {
pub field1: String,
pub field2: String,
pub field3: String,
}
impl From<Iter<'_, calamine::DataType>> for Test {
fn from(mut val: Iter<'_, calamine::DataType>) -> Self {
Test {
field1: val.next().expect("failed").to_string(),
field2: val.next().expect("failed").to_string(),
field3: val.next().expect("failed").to_string(),
}
}
}
fn read_from_excel_sheet<'a, 'b, T: From<Iter<'a, calamine::DataType>>, P: AsRef<Path>>(
wb_path: P,
ws_name: &'b str,
) {
let mut workbook: Xlsx<_> = open_workbook(wb_path).expect("Cannot open wb");
if let Some(Ok(range)) = workbook.worksheet_range(ws_name) {
for row in range.rows().skip(1) {
let new_item = T::from(row.iter());
}
}
}
When I complied it, I got an error.
error[E0597]: `range` does not live long enough
--> src/main.rs:31:20
|
25 | fn read_from_excel_sheet<'a,'b, T: From<Iter<'a, calamine::DataType>>, P: AsRef<Path>>(wb_path: P, ws_name: &'b str) {
| -- lifetime `'a` defined here
...
29 | if let Some(Ok(range)) = workbook.worksheet_range(ws_name) {
| ----- binding `range` declared here
30 |
31 | for row in range.rows().skip(1) {
| ^^^^^^^^^^^^ borrowed value does not live long enough
32 |
33 | let new_item = T::from(row.iter());
| ------------------- argument requires that `range` is borrowed for `'a`
...
36 | }
| - `range` dropped here while still borrowed
I can understand what the error message is saying but don't know why the lifetime of range
matters. As the message points out, range
will be dropped when the program reaches the end of if
block, but at that time nothing references it because new_item
is created and dropped in each iteration and each field of Test
is owned type(String
), which means it does not depend on anything.
After serveral tries, I found a soultion, but I still don't know why it works.
fn read_from_excel_sheet<'b, T: for<'a> From<Iter<'a, calamine::DataType>>, P: AsRef<Path>>(
wb_path: P,
ws_name: &'b str,
) {
let mut workbook: Xlsx<_> = open_workbook(wb_path).expect("Cannot open wb");
if let Some(Ok(range)) = workbook.worksheet_range(ws_name) {
for row in range.rows().skip(1) {
let new_item = T::from(row.iter());
}
}
}