I try to send a rusqlite
Statement by mutable reference to a function, to let that function execute a query and pack the results into a Peekable Iterator. The compiler complains that the statement that I borrow does not live long enough.
The following program works, if I remove the comments and use alt. 2 instead of **alt.1 **.
use std::iter::Peekable;
use rusqlite::{
Error,
MappedRows,
Row,
Statement,
params,
};
fn get_mapped_rows<'stmt>(get_stmt: &'stmt mut Statement<'stmt>,
)-> Peekable<MappedRows<'stmt, impl FnMut(&Row<'_>) -> Result<i64, Error>>> {
get_stmt
.query(params![0, 0])
.unwrap()
.mapped(|row| {
Ok(row.get(0)?)
})
.peekable()
}
fn main() {
let conn = rusqlite::Connection::open("db.sqlite3")
.unwrap();
let mut get_stmt = conn
.prepare("SELECT dbl_time FROM log")
.unwrap();
// Alt. 1
let mut mapped_rows = get_mapped_rows(&mut get_stmt);
/*
// Alt. 2
let mut mapped_rows = get_stmt
.query(params![0, 0])
.unwrap()
.mapped(|row| {
let nbr: i64 = row.get(0)?;
Ok(nbr)
})
.peekable();
*/
while let Some(row_result) = mapped_rows.next() {
match row_result {
Ok(dbl_time) => { println!("dbl_time:{} is_last:{}",
dbl_time,
mapped_rows.peek().is_none()); },
_ => panic!("Error!"),
}
}
}
I would have expected the iterator returned by get_mapped_rows
to be dropped before get_stmt
and therefore I do not understand how the lifetime of the borrowed get_stmt
becomes a problem.
However the compiler says:
error[E0597]: `get_stmt` does not live long enough
--> src/main.rs:31:43
|
26 | let mut get_stmt = conn
| ------------ binding `get_stmt` declared here
...
31 | let mut mapped_rows = get_mapped_rows(&mut get_stmt);
| ^^^^^^^^^^^^^ borrowed value does not live long enough
...
53 | }
| -
| |
| `get_stmt` dropped here while still borrowed
| borrow might be used here, when `get_stmt` is dropped and runs the `Drop` code for type `Statement`
Edit: Originally I tried to pass two different statements into the function:
fn get_rows<'stmt>(
i: u32,
get_stmt_0: &'stmt mut Statement<'_>,
get_stmt_1: &'stmt mut Statement<'_>,
) -> Rows<'stmt> {
let stmt = if i < 42 {
get_stmt_0
} else {
get_stmt_1
};
stmt
.query(params![0, 0])
.unwrap()
}
Using &'stmt mut Statement<'_>
here leads to another problem with the compiler saying:
error: lifetime may not live long enough
--> src/main.rs:13:9
|
9 | get_stmt_0: &'stmt mut Statement<'_>,
| ---------- has type `&mut Statement<'1>`
10 | get_stmt_1: &'stmt mut Statement<'_>,
| ---------- has type `&mut Statement<'2>`
...
13 | get_stmt_0
| ^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
|
= note: requirement occurs because of a mutable reference to `Statement<'_>`
= note: mutable references are invariant over their type parameter
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> src/main.rs:15:9
|
9 | get_stmt_0: &'stmt mut Statement<'_>,
| ---------- has type `&mut Statement<'1>`
10 | get_stmt_1: &'stmt mut Statement<'_>,
| ---------- has type `&mut Statement<'2>`
...
15 | get_stmt_1
| ^^^^^^^^^^ assignment requires that `'2` must outlive `'1`
|
= note: requirement occurs because of a mutable reference to `Statement<'_>`
= note: mutable references are invariant over their type parameter
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
Here I say that both input statements and the return value should share the same lifetime. Somehow the compiler indicates that they have different types (different lifetimes '1
and '2
respectively). What does that mean? And any ideas on how to fix that?
Edit 2
Trying to introduce another lifetime parameter for the input Statements
called 'a
. Function now looks like:
fn get_rows<'stmt, 'a>(
i: u32,
get_stmt_0: &'a mut Statement<'_>,
get_stmt_1: &'a mut Statement<'_>,
) -> Rows<'stmt> where 'a: 'stmt
{
let stmt = if i < 42 {
get_stmt_0
} else {
get_stmt_1
};
stmt
.query(params![0, 0])
.unwrap()
}
From what I understand I now state (using the where
clause) that the lifetime of the Statements
must be at least as long as that of the returned Rows
. But I still get the same error as before:
error: lifetime may not live long enough
--> src/main.rs:14:9
|
9 | get_stmt_0: &'a mut Statement<'_>,
| ---------- has type `&mut Statement<'1>`
10 | get_stmt_1: &'a mut Statement<'_>,
| ---------- has type `&mut Statement<'2>`
...
14 | get_stmt_0
| ^^^^^^^^^^ assignment requires that `'1` must outlive `'2`
|
= note: requirement occurs because of a mutable reference to `Statement<'_>`
= note: mutable references are invariant over their type parameter
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
error: lifetime may not live long enough
--> src/main.rs:16:9
|
9 | get_stmt_0: &'a mut Statement<'_>,
| ---------- has type `&mut Statement<'1>`
10 | get_stmt_1: &'a mut Statement<'_>,
| ---------- has type `&mut Statement<'2>`
...
16 | get_stmt_1
| ^^^^^^^^^^ assignment requires that `'2` must outlive `'1`
|
= note: requirement occurs because of a mutable reference to `Statement<'_>`
= note: mutable references are invariant over their type parameter
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
I honestly don't understand if the problem has to do with lifetimes or with selecting between two different input references.
The compiler is complaining about the lifetime within the Statement
s being different, not the lifetime of the references. You need a separate lifetime to convey to the compiler that they are the same rather than leaving it to infer different lifetimes by using '_
. This compiles:
use rusqlite::{params, Rows, Statement};
fn get_rows<'a, 'stmt>(
i: u32,
get_stmt_0: &'stmt mut Statement<'a>,
get_stmt_1: &'stmt mut Statement<'a>,
) -> Rows<'stmt> {
let stmt = if i < 42 {
get_stmt_0
} else {
get_stmt_1
};
stmt.query(params![0, 0]).unwrap()
}